From 30a19ca51d2a057c9a837268a415135289c21352 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 09:46:57 -0700 Subject: [PATCH 01/71] move the create_event function to the items file --- worlds/sims4/Items.py | 3 +++ worlds/sims4/__init__.py | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/sims4/Items.py b/worlds/sims4/Items.py index e9670b592fc1..db9865e8a0a9 100644 --- a/worlds/sims4/Items.py +++ b/worlds/sims4/Items.py @@ -21,6 +21,9 @@ class ItemData(NamedTuple): class Sims4Item(Item): game: str = "The Sims 4" +def create_event(self, event: str): + return Sims4Item(event, ItemClassification.progression, None, self.player) + skills_table: dict[int, ItemDict] = {} diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 6371d0123647..df6ebb77be6d 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -70,9 +70,6 @@ def create_item(self, name: str) -> Item: item_table[item_id]["classification"], item_id, player=self.player) - def create_event(self, event: str): - return Sims4Item(event, ItemClassification.progression, None, self.player) - def create_items(self) -> None: used_dlc = set(self.options.expansion_packs.value | self.options.game_packs.value | self.options.stuff_packs.value) pool = [] From d83657df3ed231e92b2a01bf21ca181ac114b7e6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 09:55:20 -0700 Subject: [PATCH 02/71] Revert "move the create_event function to the items file" This reverts commit 30a19ca51d2a057c9a837268a415135289c21352. --- worlds/sims4/Items.py | 3 --- worlds/sims4/__init__.py | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/sims4/Items.py b/worlds/sims4/Items.py index db9865e8a0a9..e9670b592fc1 100644 --- a/worlds/sims4/Items.py +++ b/worlds/sims4/Items.py @@ -21,9 +21,6 @@ class ItemData(NamedTuple): class Sims4Item(Item): game: str = "The Sims 4" -def create_event(self, event: str): - return Sims4Item(event, ItemClassification.progression, None, self.player) - skills_table: dict[int, ItemDict] = {} diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index df6ebb77be6d..6371d0123647 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -70,6 +70,9 @@ def create_item(self, name: str) -> Item: item_table[item_id]["classification"], item_id, player=self.player) + def create_event(self, event: str): + return Sims4Item(event, ItemClassification.progression, None, self.player) + def create_items(self) -> None: used_dlc = set(self.options.expansion_packs.value | self.options.game_packs.value | self.options.stuff_packs.value) pool = [] From 57b5ca08f4505ae8b18aae6238d5b24779e8481b Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 10:05:32 -0700 Subject: [PATCH 03/71] pass the world, player and options instead of getting them --- worlds/sims4/Rules.py | 7 ++----- worlds/sims4/__init__.py | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index c17fe64357e5..803fed11a933 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING -from BaseClasses import CollectionState +from BaseClasses import CollectionState, MultiWorld from worlds.AutoWorld import LogicMixin from .Names.DLC import ExpansionNames, GamePackNames, StuffNames from ..generic.Rules import set_rule @@ -19,10 +19,7 @@ def _sims4_rule(self, player: int): return True -def set_rules(sims4_world: Sims4World): - world = sims4_world.multiworld - player = sims4_world.player - options: Sims4Options = sims4_world.options +def set_rules(world: MultiWorld, player: int, options: Sims4Options): # Career Rules # TODO relearn how the career locations send, and then refactor this to use has_skill diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 6371d0123647..3f158a4c4f83 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -126,7 +126,7 @@ def create_regions(self): self.multiworld.regions.append(menu) def set_rules(self) -> None: - ts4_set_rules(self) + ts4_set_rules(self.multiworld, self.player, self.options) def fill_slot_data(self) -> Mapping[str, Any]: # slot_data = self.options.as_dict("goal", "career", "expansion_packs", "game_packs", "stuff_packs", "cas_kits", "build_kits") From aaf7a414512684f092da09e9df0357743bc0628e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 10:07:42 -0700 Subject: [PATCH 04/71] start making a completion condition function --- worlds/sims4/Rules.py | 113 ++++++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 803fed11a933..7784e4c44400 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -654,61 +654,6 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): set_rule(world.get_location(f"{skill} {level}", player), lambda state, s=skill, l=level: has_skill(state, s, player, l)) - if options.goal.value == options.goal.option_bodybuilder: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_bodybuilder, player), player=player) - elif options.goal.value == options.goal.option_painter_extraordinaire: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), player=player) - elif options.goal.value == options.goal.option_bestselling_author: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_bestselling_author, player), player=player) - elif options.goal.value == options.goal.option_musical_genius: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_musical_genius, player), player=player) - elif options.goal.value == options.goal.option_public_enemy: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_public_enemy, player), player=player) - elif options.goal.value == options.goal.option_chief_of_mischief: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), player=player) - elif options.goal.value == options.goal.option_master_chef: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_master_chef, player), player=player) - elif options.goal.value == options.goal.option_master_mixologist: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_master_mixologist, player), player=player) - elif options.goal.value == options.goal.option_renaissance_sim: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), player=player) - elif options.goal.value == options.goal.option_nerd_brain: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_nerd_brain, player), player=player) - elif options.goal.value == options.goal.option_computer_whiz: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_computer_whiz, player), player=player) - elif options.goal.value == options.goal.option_serial_romantic: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_serial_romantic, player), player=player) - elif options.goal.value == options.goal.option_freelance_botanist: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), player=player) - elif options.goal.value == options.goal.option_the_curator: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_the_curator, player), player=player) - elif options.goal.value == options.goal.option_angling_ace: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_angling_ace, player), player=player) - elif options.goal.value == options.goal.option_joke_star: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_joke_star, player), player=player) - elif options.goal.value == options.goal.option_friend_of_the_world: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), player=player) - elif options.goal.value == options.goal.option_neighborly_advisor: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), player=player) - def count_skills_over(threshold: int, state, player) -> int: total_count = 0 @@ -763,3 +708,61 @@ def has_skill(state: CollectionState, skill: str, player: int, skill_level: int) def has_multiple_skills(state: CollectionState, skills_and_levels: dict[str, int], player: int): skills = list(skills_and_levels.keys()) return has_skill(state, skills[0], player, skills_and_levels[skills[0]]) and has_skill(state, skills[1], player, skills_and_levels[skills[1]]) + +def set_completion_condition(world: MultiWorld, player: int, options: Sims4Options): + goal = options.goal + + if options.goal.value == options.goal.option_bodybuilder: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_bodybuilder, player), player=player) + elif options.goal.value == options.goal.option_painter_extraordinaire: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), player=player) + elif options.goal.value == options.goal.option_bestselling_author: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_bestselling_author, player), player=player) + elif options.goal.value == options.goal.option_musical_genius: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_musical_genius, player), player=player) + elif options.goal.value == options.goal.option_public_enemy: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_public_enemy, player), player=player) + elif options.goal.value == options.goal.option_chief_of_mischief: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), player=player) + elif options.goal.value == options.goal.option_master_chef: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_master_chef, player), player=player) + elif options.goal.value == options.goal.option_master_mixologist: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_master_mixologist, player), player=player) + elif options.goal.value == options.goal.option_renaissance_sim: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), player=player) + elif options.goal.value == options.goal.option_nerd_brain: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_nerd_brain, player), player=player) + elif options.goal.value == options.goal.option_computer_whiz: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_computer_whiz, player), player=player) + elif options.goal.value == options.goal.option_serial_romantic: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_serial_romantic, player), player=player) + elif options.goal.value == options.goal.option_freelance_botanist: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), player=player) + elif options.goal.value == options.goal.option_the_curator: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_the_curator, player), player=player) + elif options.goal.value == options.goal.option_angling_ace: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_angling_ace, player), player=player) + elif options.goal.value == options.goal.option_joke_star: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_joke_star, player), player=player) + elif options.goal.value == options.goal.option_friend_of_the_world: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), player=player) + elif options.goal.value == options.goal.option_neighborly_advisor: + world.completion_condition[player] = lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), player=player) \ No newline at end of file From 05a7168bcc39a5b7dd9743261e84df9022395f4f Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 10:09:34 -0700 Subject: [PATCH 05/71] use the local goal variable --- worlds/sims4/Rules.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 7784e4c44400..95151cdea888 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -712,57 +712,57 @@ def has_multiple_skills(state: CollectionState, skills_and_levels: dict[str, int def set_completion_condition(world: MultiWorld, player: int, options: Sims4Options): goal = options.goal - if options.goal.value == options.goal.option_bodybuilder: + if goal.value == goal.option_bodybuilder: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_bodybuilder, player), player=player) - elif options.goal.value == options.goal.option_painter_extraordinaire: + elif goal.value == goal.option_painter_extraordinaire: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), player=player) - elif options.goal.value == options.goal.option_bestselling_author: + elif goal.value == goal.option_bestselling_author: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_bestselling_author, player), player=player) - elif options.goal.value == options.goal.option_musical_genius: + elif goal.value == goal.option_musical_genius: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_musical_genius, player), player=player) - elif options.goal.value == options.goal.option_public_enemy: + elif goal.value == goal.option_public_enemy: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_public_enemy, player), player=player) - elif options.goal.value == options.goal.option_chief_of_mischief: + elif goal.value == goal.option_chief_of_mischief: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), player=player) - elif options.goal.value == options.goal.option_master_chef: + elif goal.value ==goal.option_master_chef: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_master_chef, player), player=player) - elif options.goal.value == options.goal.option_master_mixologist: + elif goal.value == goal.option_master_mixologist: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_master_mixologist, player), player=player) - elif options.goal.value == options.goal.option_renaissance_sim: + elif goal.value == goal.option_renaissance_sim: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), player=player) - elif options.goal.value == options.goal.option_nerd_brain: + elif goal.value == goal.option_nerd_brain: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_nerd_brain, player), player=player) - elif options.goal.value == options.goal.option_computer_whiz: + elif goal.value == goal.option_computer_whiz: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_computer_whiz, player), player=player) - elif options.goal.value == options.goal.option_serial_romantic: + elif goal.value == goal.option_serial_romantic: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_serial_romantic, player), player=player) - elif options.goal.value == options.goal.option_freelance_botanist: + elif goal.value == goal.option_freelance_botanist: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), player=player) - elif options.goal.value == options.goal.option_the_curator: + elif goal.value == goal.option_the_curator: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_the_curator, player), player=player) - elif options.goal.value == options.goal.option_angling_ace: + elif goal.value == goal.option_angling_ace: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_angling_ace, player), player=player) - elif options.goal.value == options.goal.option_joke_star: + elif goal.value == goal.option_joke_star: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_joke_star, player), player=player) - elif options.goal.value == options.goal.option_friend_of_the_world: + elif goal.value == goal.option_friend_of_the_world: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), player=player) - elif options.goal.value == options.goal.option_neighborly_advisor: + elif goal.value == goal.option_neighborly_advisor: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), player=player) \ No newline at end of file From 3024298169dd419f97105e777bc54649f776a928 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 10:10:13 -0700 Subject: [PATCH 06/71] call the new function --- worlds/sims4/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 3f158a4c4f83..fef69dec9c94 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -12,7 +12,7 @@ from .Options import Sims4Options from .Regions import sims4_careers, sims4_aspiration_milestones, sims4_skill_dependencies, \ sims4_regions -from .Rules import set_rules as ts4_set_rules +from .Rules import set_completion_condition, set_rules as ts4_set_rules from .Groups import location_name_groups, item_name_groups from .UT import UTMixin from .Settings import Sims4Settings @@ -127,6 +127,7 @@ def create_regions(self): def set_rules(self) -> None: ts4_set_rules(self.multiworld, self.player, self.options) + set_completion_condition(self.multiworld, self.player, self.options) def fill_slot_data(self) -> Mapping[str, Any]: # slot_data = self.options.as_dict("goal", "career", "expansion_packs", "game_packs", "stuff_packs", "cas_kits", "build_kits") From c44a509338c666a008137101d8087ed4e96a0b53 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 10:11:46 -0700 Subject: [PATCH 07/71] make a local variable for the goal value and reference it --- worlds/sims4/Rules.py | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 95151cdea888..b621a0cf52a4 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -711,58 +711,59 @@ def has_multiple_skills(state: CollectionState, skills_and_levels: dict[str, int def set_completion_condition(world: MultiWorld, player: int, options: Sims4Options): goal = options.goal + goal_value = goal.value - if goal.value == goal.option_bodybuilder: + if goal_value == goal.option_bodybuilder: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_bodybuilder, player), player=player) - elif goal.value == goal.option_painter_extraordinaire: + elif goal_value == goal.option_painter_extraordinaire: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), player=player) - elif goal.value == goal.option_bestselling_author: + elif goal_value == goal.option_bestselling_author: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_bestselling_author, player), player=player) - elif goal.value == goal.option_musical_genius: + elif goal_value == goal.option_musical_genius: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_musical_genius, player), player=player) - elif goal.value == goal.option_public_enemy: + elif goal_value == goal.option_public_enemy: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_public_enemy, player), player=player) - elif goal.value == goal.option_chief_of_mischief: + elif goal_value == goal.option_chief_of_mischief: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), player=player) - elif goal.value ==goal.option_master_chef: + elif goal_value == goal.option_master_chef: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_master_chef, player), player=player) - elif goal.value == goal.option_master_mixologist: + elif goal_value == goal.option_master_mixologist: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_master_mixologist, player), player=player) - elif goal.value == goal.option_renaissance_sim: + elif goal_value == goal.option_renaissance_sim: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), player=player) - elif goal.value == goal.option_nerd_brain: + elif goal_value == goal.option_nerd_brain: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_nerd_brain, player), player=player) - elif goal.value == goal.option_computer_whiz: + elif goal_value == goal.option_computer_whiz: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_computer_whiz, player), player=player) - elif goal.value == goal.option_serial_romantic: + elif goal_value == goal.option_serial_romantic: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_serial_romantic, player), player=player) - elif goal.value == goal.option_freelance_botanist: + elif goal_value == goal.option_freelance_botanist: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), player=player) - elif goal.value == goal.option_the_curator: + elif goal_value == goal.option_the_curator: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_the_curator, player), player=player) - elif goal.value == goal.option_angling_ace: + elif goal_value == goal.option_angling_ace: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_angling_ace, player), player=player) - elif goal.value == goal.option_joke_star: + elif goal_value == goal.option_joke_star: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_joke_star, player), player=player) - elif goal.value == goal.option_friend_of_the_world: + elif goal_value == goal.option_friend_of_the_world: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), player=player) - elif goal.value == goal.option_neighborly_advisor: + elif goal_value == goal.option_neighborly_advisor: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), player=player) \ No newline at end of file From f0a92eaa6b2010220ca7223d515835551108356d Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 10:14:27 -0700 Subject: [PATCH 08/71] make variables for the pack options --- worlds/sims4/Rules.py | 54 +++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index b621a0cf52a4..5df00e407304 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -585,67 +585,71 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): SkillNames.base_skill_rocket_science: (3, 11), } - if ExpansionNames.get_to_work in options.expansion_packs.value: + eps = options.expansion_packs.value + gps = options.game_packs.value + sps = options.stuff_packs.value + + if ExpansionNames.get_to_work in eps: skills[SkillNames.gtw_baking_skill] = (3, 11) - if ExpansionNames.get_together in options.expansion_packs.value: + if ExpansionNames.get_together in eps: skills[SkillNames.gt_dancing_skill] = (3, 6) skills[SkillNames.gt_djmixing_skill] = (3, 11) - if ExpansionNames.city_living in options.expansion_packs.value: + if ExpansionNames.city_living in eps: skills[SkillNames.cl_singing_skill] = (3, 11) - if ExpansionNames.cats_and_dogs in options.expansion_packs.value: + if ExpansionNames.cats_and_dogs in eps: skills[SkillNames.cnd_pettraining_skill] = (3, 6) skills[SkillNames.cnd_veterinarian_skill] = (3,11) - if ExpansionNames.seasons in options.expansion_packs.value: + if ExpansionNames.seasons in eps: skills[SkillNames.se_flowerarranging_skill] = (3, 11) - if ExpansionNames.get_famous in options.expansion_packs.value: + if ExpansionNames.get_famous in eps: skills[SkillNames.gf_acting_skill] = (3, 11) skills[SkillNames.gf_mediaproduction_skill] = (3, 6) - if ExpansionNames.discover_university in options.expansion_packs.value: + if ExpansionNames.discover_university in eps: skills[SkillNames.du_robotics_skill] = (3, 11) skills[SkillNames.du_researchanddebate_skill] = (3, 11) - if ExpansionNames.eco_lifestyle in options.expansion_packs.value: + if ExpansionNames.eco_lifestyle in eps: skills[SkillNames.el_fabrication_skill] = (3, 11) skills[SkillNames.el_juicefizzing_skill] = (3, 6) - if ExpansionNames.snowy_escape in options.expansion_packs.value: + if ExpansionNames.snowy_escape in eps: skills[SkillNames.sy_rock_climbing_skill] = (3, 11) skills[SkillNames.sy_skiing_skill] = (3, 11) skills[SkillNames.sy_snowboarding_skill] = (3, 11) - if ExpansionNames.cottage_living in options.expansion_packs.value: + if ExpansionNames.cottage_living in eps: skills[SkillNames.cgl_cross_stitch_skill] = (3, 6) - if ExpansionNames.high_school_years in options.expansion_packs.value: + if ExpansionNames.high_school_years in eps: skills[SkillNames.hsy_entrepreneur_skill] = (3, 6) - if ExpansionNames.horse_ranch in options.expansion_packs.value: + if ExpansionNames.horse_ranch in eps: skills[SkillNames.hr_horse_riding_skill] = (3, 11) skills[SkillNames.hr_nectar_making_skill] = (3, 6) - if ExpansionNames.lovestruck in options.expansion_packs.value: + if ExpansionNames.lovestruck in eps: skills[SkillNames.lv_romance_skill] = (3, 11) - if ExpansionNames.life_and_death in options.expansion_packs.value: + if ExpansionNames.life_and_death in eps: skills[SkillNames.lnd_thanatology_skill] = (3, 6) - if ExpansionNames.business_and_hobbies in options.expansion_packs.value: + if ExpansionNames.business_and_hobbies in eps: skills[SkillNames.bnh_pottery_skill] = (3, 11) skills[SkillNames.bnh_tattooing_skill] = (3, 11) - if ExpansionNames.enchanted_by_nature in options.expansion_packs.value: + if ExpansionNames.enchanted_by_nature in eps: skills[SkillNames.ebn_apothecary_skill] = (3, 11) skills[SkillNames.ebn_natural_living_skill] = (3, 11) - if GamePackNames.outdoor_retreat in options.game_packs.value: + if GamePackNames.outdoor_retreat in gps: skills[SkillNames.or_herbalism_skill] = (3, 11) - if GamePackNames.spa_day in options.game_packs.value: + if GamePackNames.spa_day in gps: skills[SkillNames.sd_wellness_skill] = (3, 11) - if GamePackNames.vampires in options.game_packs.value: + if GamePackNames.vampires in gps: skills[SkillNames.vamp_pipeorgan_skill] = (3, 11) skills[SkillNames.vamp_vampirelore_skill] = (3, 16) - if GamePackNames.parenthood in options.game_packs.value: + if GamePackNames.parenthood in gps: skills[SkillNames.ph_parenting_skill] = (3, 11) - if GamePackNames.jungle_adventure in options.game_packs.value: + if GamePackNames.jungle_adventure in gps: skills[SkillNames.ja_archaeology_skill] = (3, 11) skills[SkillNames.ja_sevadoradianculture_skill] = (3, 6) - if StuffNames.bowling_night in options.stuff_packs.value: + if StuffNames.bowling_night in sps: skills[SkillNames.bns_bowling_skill] = (3, 6) - if StuffNames.nifty_knitting in options.stuff_packs.value: + if StuffNames.nifty_knitting in sps: skills[SkillNames.nk_knitting_skill] = (3, 11) - if StuffNames.paranormal in options.stuff_packs.value: + if StuffNames.paranormal in sps: skills[SkillNames.pa_medium_skill] = (3, 6) - if StuffNames.crystal_creations in options.stuff_packs.value: + if StuffNames.crystal_creations in sps: skills[SkillNames.cc_gemology_skill] = (3, 11) for skill, (low, high) in skills.items(): From 6b045c8f83e8951b44e773d6c8a9250bd123093d Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 10:17:21 -0700 Subject: [PATCH 09/71] more optimizing --- worlds/sims4/Rules.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 5df00e407304..ca9a3b298359 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -420,28 +420,32 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): # Part Time Jobs # Aspirations - if options.goal.value == options.goal.option_bodybuilder: + + goal = options.goal + goal_value = goal.value + + if goal_value == goal.option_bodybuilder: set_rule(world.get_location(AspirationNames.base_aspiration_exercise_demon, player), lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 4)) set_rule(world.get_location(AspirationNames.base_aspiration_fit_to_a_t, player), lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) - elif options.goal.value == options.goal.option_painter_extraordinaire: + elif goal_value == goal.option_painter_extraordinaire: set_rule(world.get_location(AspirationNames.base_aspiration_fine_artist, player), lambda state: has_skill(state, SkillNames.base_skill_painting, player, 4)) set_rule(world.get_location(AspirationNames.base_aspiration_brushing_with_greatness, player), lambda state: has_skill(state, SkillNames.base_skill_painting, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) - elif options.goal.value == options.goal.option_bestselling_author: + elif goal_value == goal.option_bestselling_author: set_rule(world.get_location(AspirationNames.base_aspiration_competent_wordsmith, player), lambda state: has_skill(state, SkillNames.base_skill_writing, player, 4)) set_rule(world.get_location(AspirationNames.base_aspiration_novelest_novelist, player), lambda state: has_skill(state, SkillNames.base_skill_writing, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_bestselling_author, player), lambda state: has_skill(state, SkillNames.base_skill_writing, player, 10)) - elif options.goal.value == options.goal.option_musical_genius: + elif goal_value == goal.option_musical_genius: set_rule(world.get_location(AspirationNames.base_aspiration_fine_tuned, player), lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 4) or has_skill(state, SkillNames.base_skill_violin, player, 4) @@ -454,21 +458,21 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 10) or has_skill(state, SkillNames.base_skill_violin, player, 10) or has_skill(state, SkillNames.base_skill_piano, player, 10)) - elif options.goal.value == options.goal.option_public_enemy: + elif goal_value == goal.option_public_enemy: set_rule(world.get_location(AspirationNames.base_aspiration_criminal_mind, player), lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) set_rule(world.get_location(AspirationNames.base_aspiration_public_enemy, player), lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 8) and has_skill(state, SkillNames.base_skill_programming, player, 4)) - elif options.goal.value == options.goal.option_chief_of_mischief: + elif goal_value == goal.option_chief_of_mischief: set_rule(world.get_location(AspirationNames.base_aspiration_artful_trickster, player), lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) set_rule(world.get_location(AspirationNames.base_aspiration_professional_prankster, player), lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 10)) - elif options.goal.value == options.goal.option_master_chef: + elif goal_value == goal.option_master_chef: set_rule(world.get_location(AspirationNames.base_aspiration_captain_cook, player), lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) set_rule(world.get_location(AspirationNames.base_aspiration_culinary_artist, player), @@ -479,7 +483,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): or (has_skill(state, SkillNames.base_skill_gourmet, player, 5) and has_skill(state, SkillNames.base_skill_mixology, player, 7) and has_skill(state, SkillNames.base_skill_charisma, player, 4))) - elif options.goal.value == options.goal.option_master_mixologist: + elif goal_value == goal.option_master_mixologist: set_rule(world.get_location(AspirationNames.base_aspiration_electric_mixer, player), lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 4)) set_rule(world.get_location(AspirationNames.base_aspiration_beverage_boss, player), @@ -488,7 +492,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): set_rule(world.get_location(AspirationNames.base_aspiration_master_mixologist, player), lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 10) and has_skill(state, SkillNames.base_skill_cooking, player, 4)) - elif options.goal.value == options.goal.option_renaissance_sim: + elif goal_value == goal.option_renaissance_sim: set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) set_rule(world.get_location(AspirationNames.base_aspiration_jack_of_some_trades, player), @@ -497,7 +501,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: count_skills_over(3, state, player) >= 5) set_rule(world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), lambda state: count_skills_over(6, state, player) >= 6) - elif options.goal.value == options.goal.option_nerd_brain: + elif goal_value == goal.option_nerd_brain: set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), lambda state: has_skill(state, SkillNames.base_skill_logic, player, 3)) set_rule(world.get_location(AspirationNames.base_aspiration_erudite, player), @@ -507,7 +511,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): set_rule(world.get_location(AspirationNames.base_aspiration_nerd_brain, player), lambda state: has_skill(state, SkillNames.base_skill_logic, player, 10) and has_skill(state, SkillNames.base_skill_handiness, player, 5)) - elif options.goal.value == options.goal.option_computer_whiz: + elif goal_value == goal.option_computer_whiz: set_rule(world.get_location(AspirationNames.base_aspiration_technically_adept, player), lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) set_rule(world.get_location(AspirationNames.base_aspiration_computer_geek, player), @@ -515,28 +519,28 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): set_rule(world.get_location(AspirationNames.base_aspiration_computer_whiz, player), lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7) and has_skill(state, SkillNames.base_skill_video_gaming, player, 4)) - elif options.goal.value == options.goal.option_serial_romantic: + elif goal_value == goal.option_serial_romantic: set_rule(world.get_location(AspirationNames.base_aspiration_up_to_date, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) set_rule(world.get_location(AspirationNames.base_aspiration_romance_juggler, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_serial_romantic, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - elif options.goal.value == options.goal.option_freelance_botanist: + elif goal_value == goal.option_freelance_botanist: set_rule(world.get_location(AspirationNames.base_aspiration_garden_variety, player), lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 4)) set_rule(world.get_location(AspirationNames.base_aspiration_nature_nurturer, player), lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 10)) - elif options.goal.value == options.goal.option_angling_ace: + elif goal_value == goal.option_angling_ace: set_rule(world.get_location(AspirationNames.base_aspiration_hooked, player), lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 4)) set_rule(world.get_location(AspirationNames.base_aspiration_reel_smart, player), lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_angling_ace, player), lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 10)) - elif options.goal.value == options.goal.option_joke_star: + elif goal_value == goal.option_joke_star: set_rule(world.get_location(AspirationNames.base_aspiration_practical_joker, player), lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) set_rule(world.get_location(AspirationNames.base_aspiration_standup_startup, player), @@ -549,14 +553,14 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 10) and (has_skill(state, SkillNames.base_skill_guitar, player, 3) or has_skill(state, SkillNames.base_skill_violin, player, 3))) - elif options.goal.value == options.goal.option_friend_of_the_world: + elif goal_value == goal.option_friend_of_the_world: set_rule(world.get_location(AspirationNames.base_aspiration_well_liked, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) set_rule(world.get_location(AspirationNames.base_aspiration_super_friend, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 10)) - elif options.goal.value == options.goal.option_neighborly_advisor: + elif goal_value == goal.option_neighborly_advisor: set_rule(world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) From 14b2e5249c25c32ca8456e7d64b1a59052a65556 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 10:18:25 -0700 Subject: [PATCH 10/71] more optimizing again --- worlds/sims4/Rules.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index ca9a3b298359..327afefc8370 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -24,8 +24,10 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): # Career Rules # TODO relearn how the career locations send, and then refactor this to use has_skill + career = options.career + # Athlete - if CareerNames.base_career_athlete in options.career: + if CareerNames.base_career_athlete in career: set_rule(world.get_location(CareerNames.base_career_athlete_4, player), lambda state: state.has(SkillNames.base_skill_charisma, player, count=1) and state.has(SkillNames.base_skill_fitness, player, count=1)) @@ -66,7 +68,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) and state.has(SkillNames.base_skill_fitness, player, count=8)) # Astronaut - if CareerNames.base_career_astronaut in options.career: + if CareerNames.base_career_astronaut in career: set_rule(world.get_location(CareerNames.base_career_astronaut_4, player), lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) set_rule(world.get_location(CareerNames.base_career_astronaut_5, player), @@ -95,7 +97,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: state.has(SkillNames.base_skill_rocket_science, player, count=2) and state.has(SkillNames.base_skill_fitness, player, count=8)) # Business - if CareerNames.base_career_business in options.career: + if CareerNames.base_career_business in career: set_rule(world.get_location(CareerNames.base_career_business_5, player), lambda state: state.has(SkillNames.base_skill_charisma, player, count=1)) set_rule(world.get_location(CareerNames.base_career_business_6, player), @@ -125,7 +127,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) and state.has(SkillNames.base_skill_logic, player, count=8)) # Criminal - if CareerNames.base_career_criminal in options.career: + if CareerNames.base_career_criminal in career: set_rule(world.get_location(CareerNames.base_career_criminal_4, player), lambda state: state.has(SkillNames.base_skill_mischief, player, count=1)) set_rule(world.get_location(CareerNames.base_career_criminal_5, player), @@ -157,7 +159,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: state.has(SkillNames.base_skill_mischief, player, count=8) and state.has(SkillNames.base_skill_programming, player, count=6)) # Culinary - if CareerNames.base_career_culinary in options.career: + if CareerNames.base_career_culinary in career: set_rule(world.get_location(CareerNames.base_career_culinary_5, player), lambda state: state.has(SkillNames.base_skill_cooking, player, count=1) and state.has(SkillNames.base_skill_mixology, player, count=1)) @@ -200,7 +202,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): and state.has(SkillNames.base_skill_charisma, player, count=6) and state.has(SkillNames.base_skill_cooking, player, count=2)) # Entertainer - if CareerNames.base_career_entertainer in options.career: + if CareerNames.base_career_entertainer in career: set_rule(world.get_location(CareerNames.base_career_entertainer_5A, player), lambda state: (state.has(SkillNames.base_skill_guitar, player, count=1) or state.has(SkillNames.base_skill_violin, player, count=1)) @@ -241,7 +243,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: state.has(SkillNames.base_skill_comedy, player, count=8) and state.has(SkillNames.base_skill_charisma, player, count=6)) # Painter - if CareerNames.base_career_painter in options.career: + if CareerNames.base_career_painter in career: set_rule(world.get_location(CareerNames.base_career_painter_4, player), lambda state: state.has(SkillNames.base_skill_painting, player, count=2)) set_rule(world.get_location(CareerNames.base_career_painter_5, player), @@ -269,7 +271,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: state.has(SkillNames.base_skill_painting, player, count=8) and state.has(SkillNames.base_skill_charisma, player, count=4)) # Secret Agent - if CareerNames.base_career_secret_agent in options.career: + if CareerNames.base_career_secret_agent in career: set_rule(world.get_location(CareerNames.base_career_secret_agent_4, player), lambda state: state.has(SkillNames.base_skill_logic, player, count=1) and state.has(SkillNames.base_skill_charisma, player, count=1)) @@ -352,7 +354,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): and state.has(SkillNames.base_skill_painting, player, count=5)) # Tech Guru # TODO check project manager career logic https://discord.com/channels/731205301247803413/1079002955262480424/1403764728177758252 - if CareerNames.base_career_tech_guru in options.career: + if CareerNames.base_career_tech_guru in career: set_rule(world.get_location(CareerNames.base_career_tech_guru_4, player), lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) set_rule(world.get_location(CareerNames.base_career_tech_guru_5, player), @@ -386,7 +388,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: state.has(SkillNames.base_skill_programming, player, count=8) and state.has(SkillNames.base_skill_charisma, player, count=4)) # Writer - if CareerNames.base_career_writer in options.career: + if CareerNames.base_career_writer in career: set_rule(world.get_location(CareerNames.base_career_writer_4, player), lambda state: state.has(SkillNames.base_skill_writing, player, count=1)) set_rule(world.get_location(CareerNames.base_career_writer_5, player), From 16bad25f131aeb1f22b657ce1dea803ac296a110 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:02:50 -0700 Subject: [PATCH 11/71] move skill rules into new function --- worlds/sims4/Rules.py | 196 +++++++++++++++++++++--------------------- 1 file changed, 99 insertions(+), 97 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 327afefc8370..ae52b88ad21f 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -567,102 +567,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) # Skillchecks - - skills = { - SkillNames.base_skill_comedy: (3, 11), - SkillNames.base_skill_charisma: (3, 11), - SkillNames.base_skill_logic: (3, 11), - SkillNames.base_skill_fitness: (3, 11), - SkillNames.base_skill_writing: (3, 11), - SkillNames.base_skill_fishing: (3, 11), - SkillNames.base_skill_gardening: (3, 11), - SkillNames.base_skill_video_gaming: (3, 11), - SkillNames.base_skill_programming: (3, 11), - SkillNames.base_skill_handiness: (3, 11), - SkillNames.base_skill_cooking: (3, 11), - SkillNames.base_skill_mixology: (3, 11), - SkillNames.base_skill_gourmet: (3, 11), - SkillNames.base_skill_mischief: (3, 11), - SkillNames.base_skill_piano: (3, 11), - SkillNames.base_skill_violin: (3, 11), - SkillNames.base_skill_guitar: (3, 11), - SkillNames.base_skill_painting: (3, 11), - SkillNames.base_skill_photography: (3, 6), - SkillNames.base_skill_rocket_science: (3, 11), - } - - eps = options.expansion_packs.value - gps = options.game_packs.value - sps = options.stuff_packs.value - - if ExpansionNames.get_to_work in eps: - skills[SkillNames.gtw_baking_skill] = (3, 11) - if ExpansionNames.get_together in eps: - skills[SkillNames.gt_dancing_skill] = (3, 6) - skills[SkillNames.gt_djmixing_skill] = (3, 11) - if ExpansionNames.city_living in eps: - skills[SkillNames.cl_singing_skill] = (3, 11) - if ExpansionNames.cats_and_dogs in eps: - skills[SkillNames.cnd_pettraining_skill] = (3, 6) - skills[SkillNames.cnd_veterinarian_skill] = (3,11) - if ExpansionNames.seasons in eps: - skills[SkillNames.se_flowerarranging_skill] = (3, 11) - if ExpansionNames.get_famous in eps: - skills[SkillNames.gf_acting_skill] = (3, 11) - skills[SkillNames.gf_mediaproduction_skill] = (3, 6) - if ExpansionNames.discover_university in eps: - skills[SkillNames.du_robotics_skill] = (3, 11) - skills[SkillNames.du_researchanddebate_skill] = (3, 11) - if ExpansionNames.eco_lifestyle in eps: - skills[SkillNames.el_fabrication_skill] = (3, 11) - skills[SkillNames.el_juicefizzing_skill] = (3, 6) - if ExpansionNames.snowy_escape in eps: - skills[SkillNames.sy_rock_climbing_skill] = (3, 11) - skills[SkillNames.sy_skiing_skill] = (3, 11) - skills[SkillNames.sy_snowboarding_skill] = (3, 11) - if ExpansionNames.cottage_living in eps: - skills[SkillNames.cgl_cross_stitch_skill] = (3, 6) - if ExpansionNames.high_school_years in eps: - skills[SkillNames.hsy_entrepreneur_skill] = (3, 6) - if ExpansionNames.horse_ranch in eps: - skills[SkillNames.hr_horse_riding_skill] = (3, 11) - skills[SkillNames.hr_nectar_making_skill] = (3, 6) - if ExpansionNames.lovestruck in eps: - skills[SkillNames.lv_romance_skill] = (3, 11) - if ExpansionNames.life_and_death in eps: - skills[SkillNames.lnd_thanatology_skill] = (3, 6) - if ExpansionNames.business_and_hobbies in eps: - skills[SkillNames.bnh_pottery_skill] = (3, 11) - skills[SkillNames.bnh_tattooing_skill] = (3, 11) - if ExpansionNames.enchanted_by_nature in eps: - skills[SkillNames.ebn_apothecary_skill] = (3, 11) - skills[SkillNames.ebn_natural_living_skill] = (3, 11) - if GamePackNames.outdoor_retreat in gps: - skills[SkillNames.or_herbalism_skill] = (3, 11) - if GamePackNames.spa_day in gps: - skills[SkillNames.sd_wellness_skill] = (3, 11) - if GamePackNames.vampires in gps: - skills[SkillNames.vamp_pipeorgan_skill] = (3, 11) - skills[SkillNames.vamp_vampirelore_skill] = (3, 16) - if GamePackNames.parenthood in gps: - skills[SkillNames.ph_parenting_skill] = (3, 11) - if GamePackNames.jungle_adventure in gps: - skills[SkillNames.ja_archaeology_skill] = (3, 11) - skills[SkillNames.ja_sevadoradianculture_skill] = (3, 6) - if StuffNames.bowling_night in sps: - skills[SkillNames.bns_bowling_skill] = (3, 6) - if StuffNames.nifty_knitting in sps: - skills[SkillNames.nk_knitting_skill] = (3, 11) - if StuffNames.paranormal in sps: - skills[SkillNames.pa_medium_skill] = (3, 6) - if StuffNames.crystal_creations in sps: - skills[SkillNames.cc_gemology_skill] = (3, 11) - - for skill, (low, high) in skills.items(): - for level in range(low, high): - # print(skill, level) - set_rule(world.get_location(f"{skill} {level}", player), - lambda state, s=skill, l=level: has_skill(state, s, player, l)) + set_skill_rules(world, player, options) def count_skills_over(threshold: int, state, player) -> int: @@ -776,4 +681,101 @@ def set_completion_condition(world: MultiWorld, player: int, options: Sims4Optio world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), player=player) elif goal_value == goal.option_neighborly_advisor: world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), player=player) \ No newline at end of file + world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), player=player) + +def set_skill_rules(world: MultiWorld, player: int, options: Sims4Options): + skills = { + SkillNames.base_skill_comedy: (3, 11), + SkillNames.base_skill_charisma: (3, 11), + SkillNames.base_skill_logic: (3, 11), + SkillNames.base_skill_fitness: (3, 11), + SkillNames.base_skill_writing: (3, 11), + SkillNames.base_skill_fishing: (3, 11), + SkillNames.base_skill_gardening: (3, 11), + SkillNames.base_skill_video_gaming: (3, 11), + SkillNames.base_skill_programming: (3, 11), + SkillNames.base_skill_handiness: (3, 11), + SkillNames.base_skill_cooking: (3, 11), + SkillNames.base_skill_mixology: (3, 11), + SkillNames.base_skill_gourmet: (3, 11), + SkillNames.base_skill_mischief: (3, 11), + SkillNames.base_skill_piano: (3, 11), + SkillNames.base_skill_violin: (3, 11), + SkillNames.base_skill_guitar: (3, 11), + SkillNames.base_skill_painting: (3, 11), + SkillNames.base_skill_photography: (3, 6), + SkillNames.base_skill_rocket_science: (3, 11), + } + + eps = options.expansion_packs.value + gps = options.game_packs.value + sps = options.stuff_packs.value + + if ExpansionNames.get_to_work in eps: + skills[SkillNames.gtw_baking_skill] = (3, 11) + if ExpansionNames.get_together in eps: + skills[SkillNames.gt_dancing_skill] = (3, 6) + skills[SkillNames.gt_djmixing_skill] = (3, 11) + if ExpansionNames.city_living in eps: + skills[SkillNames.cl_singing_skill] = (3, 11) + if ExpansionNames.cats_and_dogs in eps: + skills[SkillNames.cnd_pettraining_skill] = (3, 6) + skills[SkillNames.cnd_veterinarian_skill] = (3, 11) + if ExpansionNames.seasons in eps: + skills[SkillNames.se_flowerarranging_skill] = (3, 11) + if ExpansionNames.get_famous in eps: + skills[SkillNames.gf_acting_skill] = (3, 11) + skills[SkillNames.gf_mediaproduction_skill] = (3, 6) + if ExpansionNames.discover_university in eps: + skills[SkillNames.du_robotics_skill] = (3, 11) + skills[SkillNames.du_researchanddebate_skill] = (3, 11) + if ExpansionNames.eco_lifestyle in eps: + skills[SkillNames.el_fabrication_skill] = (3, 11) + skills[SkillNames.el_juicefizzing_skill] = (3, 6) + if ExpansionNames.snowy_escape in eps: + skills[SkillNames.sy_rock_climbing_skill] = (3, 11) + skills[SkillNames.sy_skiing_skill] = (3, 11) + skills[SkillNames.sy_snowboarding_skill] = (3, 11) + if ExpansionNames.cottage_living in eps: + skills[SkillNames.cgl_cross_stitch_skill] = (3, 6) + if ExpansionNames.high_school_years in eps: + skills[SkillNames.hsy_entrepreneur_skill] = (3, 6) + if ExpansionNames.horse_ranch in eps: + skills[SkillNames.hr_horse_riding_skill] = (3, 11) + skills[SkillNames.hr_nectar_making_skill] = (3, 6) + if ExpansionNames.lovestruck in eps: + skills[SkillNames.lv_romance_skill] = (3, 11) + if ExpansionNames.life_and_death in eps: + skills[SkillNames.lnd_thanatology_skill] = (3, 6) + if ExpansionNames.business_and_hobbies in eps: + skills[SkillNames.bnh_pottery_skill] = (3, 11) + skills[SkillNames.bnh_tattooing_skill] = (3, 11) + if ExpansionNames.enchanted_by_nature in eps: + skills[SkillNames.ebn_apothecary_skill] = (3, 11) + skills[SkillNames.ebn_natural_living_skill] = (3, 11) + if GamePackNames.outdoor_retreat in gps: + skills[SkillNames.or_herbalism_skill] = (3, 11) + if GamePackNames.spa_day in gps: + skills[SkillNames.sd_wellness_skill] = (3, 11) + if GamePackNames.vampires in gps: + skills[SkillNames.vamp_pipeorgan_skill] = (3, 11) + skills[SkillNames.vamp_vampirelore_skill] = (3, 16) + if GamePackNames.parenthood in gps: + skills[SkillNames.ph_parenting_skill] = (3, 11) + if GamePackNames.jungle_adventure in gps: + skills[SkillNames.ja_archaeology_skill] = (3, 11) + skills[SkillNames.ja_sevadoradianculture_skill] = (3, 6) + if StuffNames.bowling_night in sps: + skills[SkillNames.bns_bowling_skill] = (3, 6) + if StuffNames.nifty_knitting in sps: + skills[SkillNames.nk_knitting_skill] = (3, 11) + if StuffNames.paranormal in sps: + skills[SkillNames.pa_medium_skill] = (3, 6) + if StuffNames.crystal_creations in sps: + skills[SkillNames.cc_gemology_skill] = (3, 11) + + for skill, (low, high) in skills.items(): + for level in range(low, high): + # print(skill, level) + set_rule(world.get_location(f"{skill} {level}", player), + lambda state, s=skill, l=level: has_skill(state, s, player, l)) \ No newline at end of file From 908ce2c905c2046d69367fb00c07bdb60144559e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:04:23 -0700 Subject: [PATCH 12/71] move aspiration rules into new function --- worlds/sims4/Rules.py | 289 +++++++++++++++++++++--------------------- 1 file changed, 146 insertions(+), 143 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index ae52b88ad21f..fb65a03cd4c3 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -423,148 +423,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): # Aspirations - goal = options.goal - goal_value = goal.value - - if goal_value == goal.option_bodybuilder: - set_rule(world.get_location(AspirationNames.base_aspiration_exercise_demon, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_fit_to_a_t, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) - elif goal_value == goal.option_painter_extraordinaire: - set_rule(world.get_location(AspirationNames.base_aspiration_fine_artist, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_brushing_with_greatness, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) - elif goal_value == goal.option_bestselling_author: - set_rule(world.get_location(AspirationNames.base_aspiration_competent_wordsmith, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_novelest_novelist, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_bestselling_author, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 10)) - elif goal_value == goal.option_musical_genius: - set_rule(world.get_location(AspirationNames.base_aspiration_fine_tuned, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 4) - or has_skill(state, SkillNames.base_skill_violin, player, 4) - or has_skill(state, SkillNames.base_skill_piano, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_harmonious, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 8) - or has_skill(state, SkillNames.base_skill_violin, player, 8) - or has_skill(state, SkillNames.base_skill_piano, player, 8)) - set_rule(world.get_location(AspirationNames.base_aspiration_musical_genius, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 10) - or has_skill(state, SkillNames.base_skill_violin, player, 10) - or has_skill(state, SkillNames.base_skill_piano, player, 10)) - elif goal_value == goal.option_public_enemy: - set_rule(world.get_location(AspirationNames.base_aspiration_criminal_mind, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_public_enemy, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 8) - and has_skill(state, SkillNames.base_skill_programming, player, 4)) - - elif goal_value == goal.option_chief_of_mischief: - set_rule(world.get_location(AspirationNames.base_aspiration_artful_trickster, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_professional_prankster, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 10)) - elif goal_value == goal.option_master_chef: - set_rule(world.get_location(AspirationNames.base_aspiration_captain_cook, player), - lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_culinary_artist, player), - lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_master_chef, player), - lambda state: (has_skill(state, SkillNames.base_skill_gourmet, player, 6) - and has_skill(state, SkillNames.base_skill_cooking, player, 8)) - or (has_skill(state, SkillNames.base_skill_gourmet, player, 5) - and has_skill(state, SkillNames.base_skill_mixology, player, 7) - and has_skill(state, SkillNames.base_skill_charisma, player, 4))) - elif goal_value == goal.option_master_mixologist: - set_rule(world.get_location(AspirationNames.base_aspiration_electric_mixer, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_beverage_boss, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 7) - and has_skill(state, SkillNames.base_skill_cooking, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_master_mixologist, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 10) - and has_skill(state, SkillNames.base_skill_cooking, player, 4)) - elif goal_value == goal.option_renaissance_sim: - set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) - set_rule(world.get_location(AspirationNames.base_aspiration_jack_of_some_trades, player), - lambda state: count_skills_over(2, state, player) >= 4) - set_rule(world.get_location(AspirationNames.base_aspiration_pantologist, player), - lambda state: count_skills_over(3, state, player) >= 5) - set_rule(world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), - lambda state: count_skills_over(6, state, player) >= 6) - elif goal_value == goal.option_nerd_brain: - set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_erudite, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_rocket_scientist, player), - lambda state: has_skill(state, SkillNames.base_skill_handiness, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_nerd_brain, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 10) - and has_skill(state, SkillNames.base_skill_handiness, player, 5)) - elif goal_value == goal.option_computer_whiz: - set_rule(world.get_location(AspirationNames.base_aspiration_technically_adept, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_computer_geek, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7)) - set_rule(world.get_location(AspirationNames.base_aspiration_computer_whiz, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7) - and has_skill(state, SkillNames.base_skill_video_gaming, player, 4)) - elif goal_value == goal.option_serial_romantic: - set_rule(world.get_location(AspirationNames.base_aspiration_up_to_date, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_romance_juggler, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_serial_romantic, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - elif goal_value == goal.option_freelance_botanist: - set_rule(world.get_location(AspirationNames.base_aspiration_garden_variety, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_nature_nurturer, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 10)) - elif goal_value == goal.option_angling_ace: - set_rule(world.get_location(AspirationNames.base_aspiration_hooked, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_reel_smart, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_angling_ace, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 10)) - elif goal_value == goal.option_joke_star: - set_rule(world.get_location(AspirationNames.base_aspiration_practical_joker, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_standup_startup, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_funny, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 6) - and (has_skill(state, SkillNames.base_skill_guitar, player, 3) - or has_skill(state, SkillNames.base_skill_violin, player, 3))) - set_rule(world.get_location(AspirationNames.base_aspiration_joke_star, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 10) - and (has_skill(state, SkillNames.base_skill_guitar, player, 3) - or has_skill(state, SkillNames.base_skill_violin, player, 3))) - elif goal_value == goal.option_friend_of_the_world: - set_rule(world.get_location(AspirationNames.base_aspiration_well_liked, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_super_friend, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 10)) - elif goal_value == goal.option_neighborly_advisor: - set_rule(world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) + set_aspiration_rules(world, player, options) # Skillchecks set_skill_rules(world, player, options) @@ -778,4 +637,148 @@ def set_skill_rules(world: MultiWorld, player: int, options: Sims4Options): for level in range(low, high): # print(skill, level) set_rule(world.get_location(f"{skill} {level}", player), - lambda state, s=skill, l=level: has_skill(state, s, player, l)) \ No newline at end of file + lambda state, s=skill, l=level: has_skill(state, s, player, l)) + +def set_aspiration_rules(world: MultiWorld, player: int, options: Sims4Options): + goal = options.goal + goal_value = goal.value + + if goal_value == goal.option_bodybuilder: + set_rule(world.get_location(AspirationNames.base_aspiration_exercise_demon, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_fit_to_a_t, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) + elif goal_value == goal.option_painter_extraordinaire: + set_rule(world.get_location(AspirationNames.base_aspiration_fine_artist, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_brushing_with_greatness, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) + elif goal_value == goal.option_bestselling_author: + set_rule(world.get_location(AspirationNames.base_aspiration_competent_wordsmith, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_novelest_novelist, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_bestselling_author, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 10)) + elif goal_value == goal.option_musical_genius: + set_rule(world.get_location(AspirationNames.base_aspiration_fine_tuned, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 4) + or has_skill(state, SkillNames.base_skill_violin, player, 4) + or has_skill(state, SkillNames.base_skill_piano, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_harmonious, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 8) + or has_skill(state, SkillNames.base_skill_violin, player, 8) + or has_skill(state, SkillNames.base_skill_piano, player, 8)) + set_rule(world.get_location(AspirationNames.base_aspiration_musical_genius, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 10) + or has_skill(state, SkillNames.base_skill_violin, player, 10) + or has_skill(state, SkillNames.base_skill_piano, player, 10)) + elif goal_value == goal.option_public_enemy: + set_rule(world.get_location(AspirationNames.base_aspiration_criminal_mind, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_public_enemy, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 8) + and has_skill(state, SkillNames.base_skill_programming, player, 4)) + + elif goal_value == goal.option_chief_of_mischief: + set_rule(world.get_location(AspirationNames.base_aspiration_artful_trickster, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_professional_prankster, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 10)) + elif goal_value == goal.option_master_chef: + set_rule(world.get_location(AspirationNames.base_aspiration_captain_cook, player), + lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_culinary_artist, player), + lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_master_chef, player), + lambda state: (has_skill(state, SkillNames.base_skill_gourmet, player, 6) + and has_skill(state, SkillNames.base_skill_cooking, player, 8)) + or (has_skill(state, SkillNames.base_skill_gourmet, player, 5) + and has_skill(state, SkillNames.base_skill_mixology, player, 7) + and has_skill(state, SkillNames.base_skill_charisma, player, 4))) + elif goal_value == goal.option_master_mixologist: + set_rule(world.get_location(AspirationNames.base_aspiration_electric_mixer, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_beverage_boss, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 7) + and has_skill(state, SkillNames.base_skill_cooking, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_master_mixologist, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 10) + and has_skill(state, SkillNames.base_skill_cooking, player, 4)) + elif goal_value == goal.option_renaissance_sim: + set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) + set_rule(world.get_location(AspirationNames.base_aspiration_jack_of_some_trades, player), + lambda state: count_skills_over(2, state, player) >= 4) + set_rule(world.get_location(AspirationNames.base_aspiration_pantologist, player), + lambda state: count_skills_over(3, state, player) >= 5) + set_rule(world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), + lambda state: count_skills_over(6, state, player) >= 6) + elif goal_value == goal.option_nerd_brain: + set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_erudite, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_rocket_scientist, player), + lambda state: has_skill(state, SkillNames.base_skill_handiness, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_nerd_brain, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 10) + and has_skill(state, SkillNames.base_skill_handiness, player, 5)) + elif goal_value == goal.option_computer_whiz: + set_rule(world.get_location(AspirationNames.base_aspiration_technically_adept, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_computer_geek, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7)) + set_rule(world.get_location(AspirationNames.base_aspiration_computer_whiz, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7) + and has_skill(state, SkillNames.base_skill_video_gaming, player, 4)) + elif goal_value == goal.option_serial_romantic: + set_rule(world.get_location(AspirationNames.base_aspiration_up_to_date, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_romance_juggler, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_serial_romantic, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + elif goal_value == goal.option_freelance_botanist: + set_rule(world.get_location(AspirationNames.base_aspiration_garden_variety, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_nature_nurturer, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 10)) + elif goal_value == goal.option_angling_ace: + set_rule(world.get_location(AspirationNames.base_aspiration_hooked, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_reel_smart, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_angling_ace, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 10)) + elif goal_value == goal.option_joke_star: + set_rule(world.get_location(AspirationNames.base_aspiration_practical_joker, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_standup_startup, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_funny, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 6) + and (has_skill(state, SkillNames.base_skill_guitar, player, 3) + or has_skill(state, SkillNames.base_skill_violin, player, 3))) + set_rule(world.get_location(AspirationNames.base_aspiration_joke_star, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 10) + and (has_skill(state, SkillNames.base_skill_guitar, player, 3) + or has_skill(state, SkillNames.base_skill_violin, player, 3))) + elif goal_value == goal.option_friend_of_the_world: + set_rule(world.get_location(AspirationNames.base_aspiration_well_liked, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_super_friend, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 10)) + elif goal_value == goal.option_neighborly_advisor: + set_rule(world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) \ No newline at end of file From e813dc792c1781c7792dc06fcd56e70ee01d742a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:19:01 -0700 Subject: [PATCH 13/71] cool aspiration function thing --- worlds/sims4/Rules.py | 317 +++++++++++++++++++++++------------------- 1 file changed, 175 insertions(+), 142 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index fb65a03cd4c3..5f88889c6581 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -18,6 +18,178 @@ class Sims4Logic(LogicMixin): def _sims4_rule(self, player: int): return True +def _bodybuilder(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_exercise_demon, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_fit_to_a_t, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) + +def _painter_extraordinaire(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_fine_artist, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_brushing_with_greatness, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) + +def _bestselling_author(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_competent_wordsmith, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_novelest_novelist, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_bestselling_author, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 10)) +def _musical_genius(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_fine_tuned, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 4) + or has_skill(state, SkillNames.base_skill_violin, player, 4) + or has_skill(state, SkillNames.base_skill_piano, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_harmonious, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 8) + or has_skill(state, SkillNames.base_skill_violin, player, 8) + or has_skill(state, SkillNames.base_skill_piano, player, 8)) + set_rule(world.get_location(AspirationNames.base_aspiration_musical_genius, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 10) + or has_skill(state, SkillNames.base_skill_violin, player, 10) + or has_skill(state, SkillNames.base_skill_piano, player, 10)) + +def _public_enemy(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_criminal_mind, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_public_enemy, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 8) + and has_skill(state, SkillNames.base_skill_programming, player, 4)) + +def _chief_of_mischief(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_artful_trickster, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_professional_prankster, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 10)) + +def _master_chef(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_captain_cook, player), + lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_culinary_artist, player), + lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_master_chef, player), + lambda state: (has_skill(state, SkillNames.base_skill_gourmet, player, 6) + and has_skill(state, SkillNames.base_skill_cooking, player, 8)) + or (has_skill(state, SkillNames.base_skill_gourmet, player, 5) + and has_skill(state, SkillNames.base_skill_mixology, player, 7) + and has_skill(state, SkillNames.base_skill_charisma, player, 4))) + +def _master_mixologist(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_electric_mixer, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_beverage_boss, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 7) + and has_skill(state, SkillNames.base_skill_cooking, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_master_mixologist, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 10) + and has_skill(state, SkillNames.base_skill_cooking, player, 4)) +def _renaissance_sim(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) + set_rule(world.get_location(AspirationNames.base_aspiration_jack_of_some_trades, player), + lambda state: count_skills_over(2, state, player) >= 4) + set_rule(world.get_location(AspirationNames.base_aspiration_pantologist, player), + lambda state: count_skills_over(3, state, player) >= 5) + set_rule(world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), + lambda state: count_skills_over(6, state, player) >= 6) + +def _nerd_brain(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_erudite, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_rocket_scientist, player), + lambda state: has_skill(state, SkillNames.base_skill_handiness, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_nerd_brain, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 10) + and has_skill(state, SkillNames.base_skill_handiness, player, 5)) + +def _computer_whiz(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_technically_adept, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_computer_geek, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7)) + set_rule(world.get_location(AspirationNames.base_aspiration_computer_whiz, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7) + and has_skill(state, SkillNames.base_skill_video_gaming, player, 4)) + +def _serial_romantic(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_up_to_date, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_romance_juggler, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_serial_romantic, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + +def _freelance_botanist (world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_garden_variety, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_nature_nurturer, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 10)) + +def _angling_ace(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_hooked, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_reel_smart, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_angling_ace, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 10)) + +def _joke_star(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_practical_joker, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_standup_startup, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_funny, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 6) + and (has_skill(state, SkillNames.base_skill_guitar, player, 3) + or has_skill(state, SkillNames.base_skill_violin, player, 3))) + set_rule(world.get_location(AspirationNames.base_aspiration_joke_star, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 10) + and (has_skill(state, SkillNames.base_skill_guitar, player, 3) + or has_skill(state, SkillNames.base_skill_violin, player, 3))) + +def _friend_of_the_world(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_well_liked, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_super_friend, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 10)) + +def _neighborly_advisor(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) + +ASPIRATION_RULES = { + Sims4Options.goal.option_bodybuilder: _bodybuilder, + Sims4Options.goal.option_painter_extraordinaire: _painter_extraordinaire, + Sims4Options.goal.option_bestselling_author: _bestselling_author, + Sims4Options.goal.option_musical_genius: _musical_genius, + Sims4Options.goal.option_public_enemy: _public_enemy, + Sims4Options.goal.option_chief_of_mischief: _chief_of_mischief, + Sims4Options.goal.option_master_chef: _master_chef, + Sims4Options.goal.option_master_mixologist: _master_mixologist, + Sims4Options.goal.option_renaissance_sim: _renaissance_sim, + Sims4Options.goal.option_nerd_brain: _nerd_brain, + Sims4Options.goal.option_computer_whiz: _computer_whiz, + Sims4Options.goal.option_serial_romantic: _serial_romantic, + Sims4Options.goal.option_freelance_botanist: _freelance_botanist, + Sims4Options.goal.option_angling_ace: _angling_ace, + Sims4Options.goal.option_joke_star: _joke_star, + Sims4Options.goal.option_friend_of_the_world: _friend_of_the_world, + Sims4Options.goal.option_neighborly_advisor: _neighborly_advisor, + } def set_rules(world: MultiWorld, player: int, options: Sims4Options): @@ -640,145 +812,6 @@ def set_skill_rules(world: MultiWorld, player: int, options: Sims4Options): lambda state, s=skill, l=level: has_skill(state, s, player, l)) def set_aspiration_rules(world: MultiWorld, player: int, options: Sims4Options): - goal = options.goal - goal_value = goal.value - - if goal_value == goal.option_bodybuilder: - set_rule(world.get_location(AspirationNames.base_aspiration_exercise_demon, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_fit_to_a_t, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) - elif goal_value == goal.option_painter_extraordinaire: - set_rule(world.get_location(AspirationNames.base_aspiration_fine_artist, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_brushing_with_greatness, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) - elif goal_value == goal.option_bestselling_author: - set_rule(world.get_location(AspirationNames.base_aspiration_competent_wordsmith, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_novelest_novelist, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_bestselling_author, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 10)) - elif goal_value == goal.option_musical_genius: - set_rule(world.get_location(AspirationNames.base_aspiration_fine_tuned, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 4) - or has_skill(state, SkillNames.base_skill_violin, player, 4) - or has_skill(state, SkillNames.base_skill_piano, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_harmonious, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 8) - or has_skill(state, SkillNames.base_skill_violin, player, 8) - or has_skill(state, SkillNames.base_skill_piano, player, 8)) - set_rule(world.get_location(AspirationNames.base_aspiration_musical_genius, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 10) - or has_skill(state, SkillNames.base_skill_violin, player, 10) - or has_skill(state, SkillNames.base_skill_piano, player, 10)) - elif goal_value == goal.option_public_enemy: - set_rule(world.get_location(AspirationNames.base_aspiration_criminal_mind, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_public_enemy, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 8) - and has_skill(state, SkillNames.base_skill_programming, player, 4)) - - elif goal_value == goal.option_chief_of_mischief: - set_rule(world.get_location(AspirationNames.base_aspiration_artful_trickster, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_professional_prankster, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 10)) - elif goal_value == goal.option_master_chef: - set_rule(world.get_location(AspirationNames.base_aspiration_captain_cook, player), - lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_culinary_artist, player), - lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_master_chef, player), - lambda state: (has_skill(state, SkillNames.base_skill_gourmet, player, 6) - and has_skill(state, SkillNames.base_skill_cooking, player, 8)) - or (has_skill(state, SkillNames.base_skill_gourmet, player, 5) - and has_skill(state, SkillNames.base_skill_mixology, player, 7) - and has_skill(state, SkillNames.base_skill_charisma, player, 4))) - elif goal_value == goal.option_master_mixologist: - set_rule(world.get_location(AspirationNames.base_aspiration_electric_mixer, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_beverage_boss, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 7) - and has_skill(state, SkillNames.base_skill_cooking, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_master_mixologist, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 10) - and has_skill(state, SkillNames.base_skill_cooking, player, 4)) - elif goal_value == goal.option_renaissance_sim: - set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) - set_rule(world.get_location(AspirationNames.base_aspiration_jack_of_some_trades, player), - lambda state: count_skills_over(2, state, player) >= 4) - set_rule(world.get_location(AspirationNames.base_aspiration_pantologist, player), - lambda state: count_skills_over(3, state, player) >= 5) - set_rule(world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), - lambda state: count_skills_over(6, state, player) >= 6) - elif goal_value == goal.option_nerd_brain: - set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_erudite, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_rocket_scientist, player), - lambda state: has_skill(state, SkillNames.base_skill_handiness, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_nerd_brain, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 10) - and has_skill(state, SkillNames.base_skill_handiness, player, 5)) - elif goal_value == goal.option_computer_whiz: - set_rule(world.get_location(AspirationNames.base_aspiration_technically_adept, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_computer_geek, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7)) - set_rule(world.get_location(AspirationNames.base_aspiration_computer_whiz, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7) - and has_skill(state, SkillNames.base_skill_video_gaming, player, 4)) - elif goal_value == goal.option_serial_romantic: - set_rule(world.get_location(AspirationNames.base_aspiration_up_to_date, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_romance_juggler, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_serial_romantic, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - elif goal_value == goal.option_freelance_botanist: - set_rule(world.get_location(AspirationNames.base_aspiration_garden_variety, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_nature_nurturer, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 10)) - elif goal_value == goal.option_angling_ace: - set_rule(world.get_location(AspirationNames.base_aspiration_hooked, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_reel_smart, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_angling_ace, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 10)) - elif goal_value == goal.option_joke_star: - set_rule(world.get_location(AspirationNames.base_aspiration_practical_joker, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_standup_startup, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_funny, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 6) - and (has_skill(state, SkillNames.base_skill_guitar, player, 3) - or has_skill(state, SkillNames.base_skill_violin, player, 3))) - set_rule(world.get_location(AspirationNames.base_aspiration_joke_star, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 10) - and (has_skill(state, SkillNames.base_skill_guitar, player, 3) - or has_skill(state, SkillNames.base_skill_violin, player, 3))) - elif goal_value == goal.option_friend_of_the_world: - set_rule(world.get_location(AspirationNames.base_aspiration_well_liked, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_super_friend, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 10)) - elif goal_value == goal.option_neighborly_advisor: - set_rule(world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) \ No newline at end of file + handler = ASPIRATION_RULES.get(options.goal) + if handler: + handler(world, player) \ No newline at end of file From f1fa2f14515d5cbe0883b4e3d037a4638d1c5d70 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:19:37 -0700 Subject: [PATCH 14/71] move the lookup stuff down --- worlds/sims4/Rules.py | 346 +++++++++++++++++++++--------------------- 1 file changed, 173 insertions(+), 173 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 5f88889c6581..2956691e53ed 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -18,179 +18,6 @@ class Sims4Logic(LogicMixin): def _sims4_rule(self, player: int): return True -def _bodybuilder(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_exercise_demon, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_fit_to_a_t, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), - lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) - -def _painter_extraordinaire(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_fine_artist, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_brushing_with_greatness, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), - lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) - -def _bestselling_author(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_competent_wordsmith, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_novelest_novelist, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_bestselling_author, player), - lambda state: has_skill(state, SkillNames.base_skill_writing, player, 10)) -def _musical_genius(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_fine_tuned, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 4) - or has_skill(state, SkillNames.base_skill_violin, player, 4) - or has_skill(state, SkillNames.base_skill_piano, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_harmonious, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 8) - or has_skill(state, SkillNames.base_skill_violin, player, 8) - or has_skill(state, SkillNames.base_skill_piano, player, 8)) - set_rule(world.get_location(AspirationNames.base_aspiration_musical_genius, player), - lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 10) - or has_skill(state, SkillNames.base_skill_violin, player, 10) - or has_skill(state, SkillNames.base_skill_piano, player, 10)) - -def _public_enemy(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_criminal_mind, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_public_enemy, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 8) - and has_skill(state, SkillNames.base_skill_programming, player, 4)) - -def _chief_of_mischief(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_artful_trickster, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_professional_prankster, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), - lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 10)) - -def _master_chef(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_captain_cook, player), - lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_culinary_artist, player), - lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_master_chef, player), - lambda state: (has_skill(state, SkillNames.base_skill_gourmet, player, 6) - and has_skill(state, SkillNames.base_skill_cooking, player, 8)) - or (has_skill(state, SkillNames.base_skill_gourmet, player, 5) - and has_skill(state, SkillNames.base_skill_mixology, player, 7) - and has_skill(state, SkillNames.base_skill_charisma, player, 4))) - -def _master_mixologist(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_electric_mixer, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_beverage_boss, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 7) - and has_skill(state, SkillNames.base_skill_cooking, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_master_mixologist, player), - lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 10) - and has_skill(state, SkillNames.base_skill_cooking, player, 4)) -def _renaissance_sim(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) - set_rule(world.get_location(AspirationNames.base_aspiration_jack_of_some_trades, player), - lambda state: count_skills_over(2, state, player) >= 4) - set_rule(world.get_location(AspirationNames.base_aspiration_pantologist, player), - lambda state: count_skills_over(3, state, player) >= 5) - set_rule(world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), - lambda state: count_skills_over(6, state, player) >= 6) - -def _nerd_brain(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_erudite, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_rocket_scientist, player), - lambda state: has_skill(state, SkillNames.base_skill_handiness, player, 5)) - set_rule(world.get_location(AspirationNames.base_aspiration_nerd_brain, player), - lambda state: has_skill(state, SkillNames.base_skill_logic, player, 10) - and has_skill(state, SkillNames.base_skill_handiness, player, 5)) - -def _computer_whiz(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_technically_adept, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_computer_geek, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7)) - set_rule(world.get_location(AspirationNames.base_aspiration_computer_whiz, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7) - and has_skill(state, SkillNames.base_skill_video_gaming, player, 4)) - -def _serial_romantic(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_up_to_date, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_romance_juggler, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_serial_romantic, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - -def _freelance_botanist (world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_garden_variety, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_nature_nurturer, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), - lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 10)) - -def _angling_ace(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_hooked, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_reel_smart, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_angling_ace, player), - lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 10)) - -def _joke_star(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_practical_joker, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_standup_startup, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) - set_rule(world.get_location(AspirationNames.base_aspiration_funny, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 6) - and (has_skill(state, SkillNames.base_skill_guitar, player, 3) - or has_skill(state, SkillNames.base_skill_violin, player, 3))) - set_rule(world.get_location(AspirationNames.base_aspiration_joke_star, player), - lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 10) - and (has_skill(state, SkillNames.base_skill_guitar, player, 3) - or has_skill(state, SkillNames.base_skill_violin, player, 3))) - -def _friend_of_the_world(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_well_liked, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) - set_rule(world.get_location(AspirationNames.base_aspiration_super_friend, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) - set_rule(world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 10)) - -def _neighborly_advisor(world: MultiWorld, player: int): - set_rule(world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), - lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) - -ASPIRATION_RULES = { - Sims4Options.goal.option_bodybuilder: _bodybuilder, - Sims4Options.goal.option_painter_extraordinaire: _painter_extraordinaire, - Sims4Options.goal.option_bestselling_author: _bestselling_author, - Sims4Options.goal.option_musical_genius: _musical_genius, - Sims4Options.goal.option_public_enemy: _public_enemy, - Sims4Options.goal.option_chief_of_mischief: _chief_of_mischief, - Sims4Options.goal.option_master_chef: _master_chef, - Sims4Options.goal.option_master_mixologist: _master_mixologist, - Sims4Options.goal.option_renaissance_sim: _renaissance_sim, - Sims4Options.goal.option_nerd_brain: _nerd_brain, - Sims4Options.goal.option_computer_whiz: _computer_whiz, - Sims4Options.goal.option_serial_romantic: _serial_romantic, - Sims4Options.goal.option_freelance_botanist: _freelance_botanist, - Sims4Options.goal.option_angling_ace: _angling_ace, - Sims4Options.goal.option_joke_star: _joke_star, - Sims4Options.goal.option_friend_of_the_world: _friend_of_the_world, - Sims4Options.goal.option_neighborly_advisor: _neighborly_advisor, - } - def set_rules(world: MultiWorld, player: int, options: Sims4Options): # Career Rules @@ -811,6 +638,179 @@ def set_skill_rules(world: MultiWorld, player: int, options: Sims4Options): set_rule(world.get_location(f"{skill} {level}", player), lambda state, s=skill, l=level: has_skill(state, s, player, l)) +def _bodybuilder(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_exercise_demon, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_fit_to_a_t, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), + lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) + +def _painter_extraordinaire(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_fine_artist, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_brushing_with_greatness, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), + lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) + +def _bestselling_author(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_competent_wordsmith, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_novelest_novelist, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_bestselling_author, player), + lambda state: has_skill(state, SkillNames.base_skill_writing, player, 10)) +def _musical_genius(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_fine_tuned, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 4) + or has_skill(state, SkillNames.base_skill_violin, player, 4) + or has_skill(state, SkillNames.base_skill_piano, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_harmonious, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 8) + or has_skill(state, SkillNames.base_skill_violin, player, 8) + or has_skill(state, SkillNames.base_skill_piano, player, 8)) + set_rule(world.get_location(AspirationNames.base_aspiration_musical_genius, player), + lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 10) + or has_skill(state, SkillNames.base_skill_violin, player, 10) + or has_skill(state, SkillNames.base_skill_piano, player, 10)) + +def _public_enemy(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_criminal_mind, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_public_enemy, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 8) + and has_skill(state, SkillNames.base_skill_programming, player, 4)) + +def _chief_of_mischief(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_artful_trickster, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_professional_prankster, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), + lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 10)) + +def _master_chef(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_captain_cook, player), + lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_culinary_artist, player), + lambda state: has_skill(state, SkillNames.base_skill_cooking, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_master_chef, player), + lambda state: (has_skill(state, SkillNames.base_skill_gourmet, player, 6) + and has_skill(state, SkillNames.base_skill_cooking, player, 8)) + or (has_skill(state, SkillNames.base_skill_gourmet, player, 5) + and has_skill(state, SkillNames.base_skill_mixology, player, 7) + and has_skill(state, SkillNames.base_skill_charisma, player, 4))) + +def _master_mixologist(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_electric_mixer, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_beverage_boss, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 7) + and has_skill(state, SkillNames.base_skill_cooking, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_master_mixologist, player), + lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 10) + and has_skill(state, SkillNames.base_skill_cooking, player, 4)) +def _renaissance_sim(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) + set_rule(world.get_location(AspirationNames.base_aspiration_jack_of_some_trades, player), + lambda state: count_skills_over(2, state, player) >= 4) + set_rule(world.get_location(AspirationNames.base_aspiration_pantologist, player), + lambda state: count_skills_over(3, state, player) >= 5) + set_rule(world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), + lambda state: count_skills_over(6, state, player) >= 6) + +def _nerd_brain(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_erudite, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_rocket_scientist, player), + lambda state: has_skill(state, SkillNames.base_skill_handiness, player, 5)) + set_rule(world.get_location(AspirationNames.base_aspiration_nerd_brain, player), + lambda state: has_skill(state, SkillNames.base_skill_logic, player, 10) + and has_skill(state, SkillNames.base_skill_handiness, player, 5)) + +def _computer_whiz(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_technically_adept, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_computer_geek, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7)) + set_rule(world.get_location(AspirationNames.base_aspiration_computer_whiz, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7) + and has_skill(state, SkillNames.base_skill_video_gaming, player, 4)) + +def _serial_romantic(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_up_to_date, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_romance_juggler, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_serial_romantic, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + +def _freelance_botanist (world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_garden_variety, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_nature_nurturer, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), + lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 10)) + +def _angling_ace(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_hooked, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_reel_smart, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_angling_ace, player), + lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 10)) + +def _joke_star(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_practical_joker, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_standup_startup, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 3)) + set_rule(world.get_location(AspirationNames.base_aspiration_funny, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 6) + and (has_skill(state, SkillNames.base_skill_guitar, player, 3) + or has_skill(state, SkillNames.base_skill_violin, player, 3))) + set_rule(world.get_location(AspirationNames.base_aspiration_joke_star, player), + lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 10) + and (has_skill(state, SkillNames.base_skill_guitar, player, 3) + or has_skill(state, SkillNames.base_skill_violin, player, 3))) + +def _friend_of_the_world(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_well_liked, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 4)) + set_rule(world.get_location(AspirationNames.base_aspiration_super_friend, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + set_rule(world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 10)) + +def _neighborly_advisor(world: MultiWorld, player: int): + set_rule(world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), + lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) + +ASPIRATION_RULES = { + Sims4Options.goal.option_bodybuilder: _bodybuilder, + Sims4Options.goal.option_painter_extraordinaire: _painter_extraordinaire, + Sims4Options.goal.option_bestselling_author: _bestselling_author, + Sims4Options.goal.option_musical_genius: _musical_genius, + Sims4Options.goal.option_public_enemy: _public_enemy, + Sims4Options.goal.option_chief_of_mischief: _chief_of_mischief, + Sims4Options.goal.option_master_chef: _master_chef, + Sims4Options.goal.option_master_mixologist: _master_mixologist, + Sims4Options.goal.option_renaissance_sim: _renaissance_sim, + Sims4Options.goal.option_nerd_brain: _nerd_brain, + Sims4Options.goal.option_computer_whiz: _computer_whiz, + Sims4Options.goal.option_serial_romantic: _serial_romantic, + Sims4Options.goal.option_freelance_botanist: _freelance_botanist, + Sims4Options.goal.option_angling_ace: _angling_ace, + Sims4Options.goal.option_joke_star: _joke_star, + Sims4Options.goal.option_friend_of_the_world: _friend_of_the_world, + Sims4Options.goal.option_neighborly_advisor: _neighborly_advisor, + } + def set_aspiration_rules(world: MultiWorld, player: int, options: Sims4Options): handler = ASPIRATION_RULES.get(options.goal) if handler: From 452bbd93b28550689625fcd84651ce85ddcc0db8 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:20:36 -0700 Subject: [PATCH 15/71] note down what i'm thinking --- worlds/sims4/Rules.py | 1 + 1 file changed, 1 insertion(+) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 2956691e53ed..cbff5a48167c 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -482,6 +482,7 @@ def has_multiple_skills(state: CollectionState, skills_and_levels: dict[str, int skills = list(skills_and_levels.keys()) return has_skill(state, skills[0], player, skills_and_levels[skills[0]]) and has_skill(state, skills[1], player, skills_and_levels[skills[1]]) +# TODO: use events for the completion condition in order to facilitate easier goal stuff, and presence in spoiler (also permits future goals to be more dynamic) def set_completion_condition(world: MultiWorld, player: int, options: Sims4Options): goal = options.goal goal_value = goal.value From 4f8144d3cb79bbf39795c937c547daf8148d57fa Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:32:06 -0700 Subject: [PATCH 16/71] new structure for career logic --- worlds/sims4/Rules.py | 805 +++++++++++++++++++++--------------------- 1 file changed, 411 insertions(+), 394 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index cbff5a48167c..6451d80eb12d 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -25,399 +25,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): career = options.career - # Athlete - if CareerNames.base_career_athlete in career: - set_rule(world.get_location(CareerNames.base_career_athlete_4, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=1) - and state.has(SkillNames.base_skill_fitness, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_athlete_5A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) - and state.has(SkillNames.base_skill_fitness, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_athlete_5B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) - and state.has(SkillNames.base_skill_fitness, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_athlete_6A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) - and state.has(SkillNames.base_skill_fitness, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_athlete_7A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) - and state.has(SkillNames.base_skill_fitness, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_athlete_8A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=3) - and state.has(SkillNames.base_skill_fitness, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_athlete_9A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=4) - and state.has(SkillNames.base_skill_fitness, player, count=7)) - set_rule(world.get_location(CareerNames.base_career_athlete_10A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) - and state.has(SkillNames.base_skill_fitness, player, count=8)) - set_rule(world.get_location(CareerNames.base_career_athlete_6B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=3) - and state.has(SkillNames.base_skill_fitness, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_athlete_7B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=3) - and state.has(SkillNames.base_skill_fitness, player, count=7)) - set_rule(world.get_location(CareerNames.base_career_athlete_8B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=4) - and state.has(SkillNames.base_skill_fitness, player, count=8)) - set_rule(world.get_location(CareerNames.base_career_athlete_9B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=5) - and state.has(SkillNames.base_skill_fitness, player, count=8)) - set_rule(world.get_location(CareerNames.base_career_athlete_10B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) - and state.has(SkillNames.base_skill_fitness, player, count=8)) - # Astronaut - if CareerNames.base_career_astronaut in career: - set_rule(world.get_location(CareerNames.base_career_astronaut_4, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_astronaut_5, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=2) - and state.has(SkillNames.base_skill_fitness, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_astronaut_6, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=3) - and state.has(SkillNames.base_skill_fitness, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_astronaut_7, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=3) - and state.has(SkillNames.base_skill_fitness, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_astronaut_8A, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=4) - and state.has(SkillNames.base_skill_fitness, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_astronaut_8B, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=4) - and state.has(SkillNames.base_skill_fitness, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_astronaut_9A, player), - lambda state: state.has(SkillNames.base_skill_fitness, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_astronaut_10A, player), - lambda state: state.has(SkillNames.base_skill_rocket_science, player, count=2) - and state.has(SkillNames.base_skill_fitness, player, count=8)) - set_rule(world.get_location(CareerNames.base_career_astronaut_9B, player), - lambda state: state.has(SkillNames.base_skill_fitness, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_astronaut_10B, player), - lambda state: state.has(SkillNames.base_skill_rocket_science, player, count=2) - and state.has(SkillNames.base_skill_fitness, player, count=8)) - # Business - if CareerNames.base_career_business in career: - set_rule(world.get_location(CareerNames.base_career_business_5, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_business_6, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_business_7A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) - and state.has(SkillNames.base_skill_logic, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_business_7B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) - and state.has(SkillNames.base_skill_logic, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_business_8A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=4) - and state.has(SkillNames.base_skill_logic, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_business_9A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) - and state.has(SkillNames.base_skill_logic, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_business_10A, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=8) - and state.has(SkillNames.base_skill_logic, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_business_8B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=3) - and state.has(SkillNames.base_skill_logic, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_business_9B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=4) - and state.has(SkillNames.base_skill_logic, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_business_10B, player), - lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) - and state.has(SkillNames.base_skill_logic, player, count=8)) - # Criminal - if CareerNames.base_career_criminal in career: - set_rule(world.get_location(CareerNames.base_career_criminal_4, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_criminal_5, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_criminal_6A, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_criminal_6B, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_criminal_7A, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_criminal_8A, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_criminal_9A, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=7) - and state.has(SkillNames.base_skill_handiness, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_criminal_10A, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=8) - and state.has(SkillNames.base_skill_handiness, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_criminal_7B, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=5) - and state.has(SkillNames.base_skill_programming, player, count=0)) - set_rule(world.get_location(CareerNames.base_career_criminal_8B, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=6) - and state.has(SkillNames.base_skill_programming, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_criminal_9B, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=7) - and state.has(SkillNames.base_skill_programming, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_criminal_10B, player), - lambda state: state.has(SkillNames.base_skill_mischief, player, count=8) - and state.has(SkillNames.base_skill_programming, player, count=6)) - # Culinary - if CareerNames.base_career_culinary in career: - set_rule(world.get_location(CareerNames.base_career_culinary_5, player), - lambda state: state.has(SkillNames.base_skill_cooking, player, count=1) - and state.has(SkillNames.base_skill_mixology, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_culinary_6A, player), - lambda state: state.has(SkillNames.base_skill_cooking, player, count=2) - and state.has(SkillNames.base_skill_mixology, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_6B, player), - lambda state: state.has(SkillNames.base_skill_cooking, player, count=2) - and state.has(SkillNames.base_skill_mixology, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_7A, player), - lambda state: state.has(SkillNames.base_skill_cooking, player, count=4) - and state.has(SkillNames.base_skill_gourmet, player, count=0) - and state.has(SkillNames.base_skill_mixology, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_8A, player), - lambda state: state.has(SkillNames.base_skill_cooking, player, count=6) - and state.has(SkillNames.base_skill_gourmet, player, count=4) - and state.has(SkillNames.base_skill_mixology, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_9A, player), - lambda state: state.has(SkillNames.base_skill_cooking, player, count=6) - and state.has(SkillNames.base_skill_gourmet, player, count=4) - and state.has(SkillNames.base_skill_mixology, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_10A, player), - lambda state: state.has(SkillNames.base_skill_cooking, player, count=8) - and state.has(SkillNames.base_skill_gourmet, player, count=6) - and state.has(SkillNames.base_skill_mixology, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_7B, player), - lambda state: state.has(SkillNames.base_skill_mixology, player, count=3) - and state.has(SkillNames.base_skill_charisma, player, count=0) - and state.has(SkillNames.base_skill_cooking, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_8B, player), - lambda state: state.has(SkillNames.base_skill_mixology, player, count=5) - and state.has(SkillNames.base_skill_charisma, player, count=2) - and state.has(SkillNames.base_skill_cooking, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_9B, player), - lambda state: state.has(SkillNames.base_skill_mixology, player, count=6) - and state.has(SkillNames.base_skill_charisma, player, count=4) - and state.has(SkillNames.base_skill_cooking, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_culinary_10B, player), - lambda state: state.has(SkillNames.base_skill_mixology, player, count=8) - and state.has(SkillNames.base_skill_charisma, player, count=6) - and state.has(SkillNames.base_skill_cooking, player, count=2)) - # Entertainer - if CareerNames.base_career_entertainer in career: - set_rule(world.get_location(CareerNames.base_career_entertainer_5A, player), - lambda state: (state.has(SkillNames.base_skill_guitar, player, count=1) - or state.has(SkillNames.base_skill_violin, player, count=1)) - and state.has(SkillNames.base_skill_comedy, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_entertainer_5B, player), - lambda state: (state.has(SkillNames.base_skill_guitar, player, count=1) - or state.has(SkillNames.base_skill_violin, player, count=1)) - and state.has(SkillNames.base_skill_comedy, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_entertainer_6A, player), - lambda state: state.has(SkillNames.base_skill_violin, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_entertainer_7A, player), - lambda state: (state.has(SkillNames.base_skill_guitar, player, count=3) - or state.has(SkillNames.base_skill_violin, player, count=3)) - and state.has(SkillNames.base_skill_piano, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_entertainer_8A, player), - lambda state: (state.has(SkillNames.base_skill_guitar, player, count=4) - or state.has(SkillNames.base_skill_violin, player, count=4)) - and state.has(SkillNames.base_skill_piano, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_entertainer_9A, player), - lambda state: (state.has(SkillNames.base_skill_guitar, player, count=5) - or state.has(SkillNames.base_skill_violin, player, count=5)) - and state.has(SkillNames.base_skill_piano, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_entertainer_10A, player), - lambda state: (state.has(SkillNames.base_skill_guitar, player, count=6) - or state.has(SkillNames.base_skill_violin, player, count=6)) - and state.has(SkillNames.base_skill_piano, player, count=8)) - set_rule(world.get_location(CareerNames.base_career_entertainer_6B, player), - lambda state: state.has(SkillNames.base_skill_comedy, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_entertainer_7B, player), - lambda state: state.has(SkillNames.base_skill_comedy, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_entertainer_8B, player), - lambda state: state.has(SkillNames.base_skill_comedy, player, count=6) - and state.has(SkillNames.base_skill_charisma, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_entertainer_9B, player), - lambda state: state.has(SkillNames.base_skill_comedy, player, count=7) - and state.has(SkillNames.base_skill_charisma, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_entertainer_10B, player), - lambda state: state.has(SkillNames.base_skill_comedy, player, count=8) - and state.has(SkillNames.base_skill_charisma, player, count=6)) - # Painter - if CareerNames.base_career_painter in career: - set_rule(world.get_location(CareerNames.base_career_painter_4, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_painter_5, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_painter_6, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_painter_7A, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_painter_7B, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_painter_8A, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_painter_9A, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=7) - and state.has(SkillNames.base_skill_logic, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_painter_10A, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=8) - and state.has(SkillNames.base_skill_logic, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_painter_8B, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_painter_9B, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=7) - and state.has(SkillNames.base_skill_charisma, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_painter_10B, player), - lambda state: state.has(SkillNames.base_skill_painting, player, count=8) - and state.has(SkillNames.base_skill_charisma, player, count=4)) - # Secret Agent - if CareerNames.base_career_secret_agent in career: - set_rule(world.get_location(CareerNames.base_career_secret_agent_4, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=1) - and state.has(SkillNames.base_skill_charisma, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_5, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=1) - and state.has(SkillNames.base_skill_charisma, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_6, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=3) - and state.has(SkillNames.base_skill_charisma, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_7, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=3) - and state.has(SkillNames.base_skill_charisma, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_8A, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=4) - and state.has(SkillNames.base_skill_charisma, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_8B, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=4) - and state.has(SkillNames.base_skill_charisma, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_9A, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=6) - and state.has(SkillNames.base_skill_charisma, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_10A, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=8) - and state.has(SkillNames.base_skill_charisma, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_9B, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_10B, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=8) - and state.has(SkillNames.base_skill_mischief, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_secret_agent_11B, player), - lambda state: state.has(SkillNames.base_skill_logic, player, count=8) - and state.has(SkillNames.base_skill_mischief, player, count=4)) - # Style Influencer - if CareerNames.base_career_style_influencer in options.career: - set_rule(world.get_location(CareerNames.base_career_style_influencer_4, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_5, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_6A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=3) - and state.has(SkillNames.base_skill_charisma, player, count=1) - and state.has(SkillNames.base_skill_painting, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_7A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=4) - and state.has(SkillNames.base_skill_charisma, player, count=3) - and state.has(SkillNames.base_skill_painting, player, count=2) - and state.has(SkillNames.base_skill_photography, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_8A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=5) - and state.has(SkillNames.base_skill_charisma, player, count=4) - and state.has(SkillNames.base_skill_painting, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_9A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=6) - and state.has(SkillNames.base_skill_charisma, player, count=5) - and state.has(SkillNames.base_skill_painting, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_10A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=7) - and state.has(SkillNames.base_skill_charisma, player, count=6) - and state.has(SkillNames.base_skill_painting, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_6B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=3) - and state.has(SkillNames.base_skill_charisma, player, count=1) - and state.has(SkillNames.base_skill_painting, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_7B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=4) - and state.has(SkillNames.base_skill_charisma, player, count=3) - and state.has(SkillNames.base_skill_painting, player, count=2) - and state.has(SkillNames.base_skill_photography, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_8B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=5) - and state.has(SkillNames.base_skill_charisma, player, count=4) - and state.has(SkillNames.base_skill_painting, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_9B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=6) - and state.has(SkillNames.base_skill_charisma, player, count=5) - and state.has(SkillNames.base_skill_painting, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_style_influencer_10B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=7) - and state.has(SkillNames.base_skill_charisma, player, count=6) - and state.has(SkillNames.base_skill_painting, player, count=5)) - # Tech Guru - # TODO check project manager career logic https://discord.com/channels/731205301247803413/1079002955262480424/1403764728177758252 - if CareerNames.base_career_tech_guru in career: - set_rule(world.get_location(CareerNames.base_career_tech_guru_4, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_5, player), - lambda state: has_skill(state, SkillNames.base_skill_programming, player, 4) - and has_skill(state, SkillNames.base_skill_video_gaming, player, 3)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_6, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=3) - and state.has(SkillNames.base_skill_video_gaming, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_7A, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=4) - and state.has(SkillNames.base_skill_video_gaming, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_7B, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=4) - and state.has(SkillNames.base_skill_video_gaming, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_8A, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=4) - and state.has(SkillNames.base_skill_video_gaming, player, count=4)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_9A, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=5) - and state.has(SkillNames.base_skill_video_gaming, player, count=6)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_10A, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=6) - and state.has(SkillNames.base_skill_video_gaming, player, count=8)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_8B, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=6) - and state.has(SkillNames.base_skill_charisma, player, count=0)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_9B, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=7) - and state.has(SkillNames.base_skill_charisma, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_tech_guru_10B, player), - lambda state: state.has(SkillNames.base_skill_programming, player, count=8) - and state.has(SkillNames.base_skill_charisma, player, count=4)) - # Writer - if CareerNames.base_career_writer in career: - set_rule(world.get_location(CareerNames.base_career_writer_4, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_writer_5, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_writer_6A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_writer_6B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_writer_7A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_writer_8A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=6) - and state.has(SkillNames.base_skill_logic, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_writer_9A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=7) - and state.has(SkillNames.base_skill_logic, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_writer_10A, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=8) - and state.has(SkillNames.base_skill_logic, player, count=3)) - set_rule(world.get_location(CareerNames.base_career_writer_7B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=5)) - set_rule(world.get_location(CareerNames.base_career_writer_8B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=6) - and state.has(SkillNames.base_skill_charisma, player, count=1)) - set_rule(world.get_location(CareerNames.base_career_writer_9B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=7) - and state.has(SkillNames.base_skill_charisma, player, count=2)) - set_rule(world.get_location(CareerNames.base_career_writer_10B, player), - lambda state: state.has(SkillNames.base_skill_writing, player, count=8) - and state.has(SkillNames.base_skill_charisma, player, count=3)) + # Part Time Jobs # Aspirations @@ -815,4 +423,413 @@ def _neighborly_advisor(world: MultiWorld, player: int): def set_aspiration_rules(world: MultiWorld, player: int, options: Sims4Options): handler = ASPIRATION_RULES.get(options.goal) if handler: - handler(world, player) \ No newline at end of file + handler(world, player) + +def _career_athlete(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_athlete_4, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=1) + and state.has(SkillNames.base_skill_fitness, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_athlete_5A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) + and state.has(SkillNames.base_skill_fitness, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_athlete_5B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) + and state.has(SkillNames.base_skill_fitness, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_athlete_6A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) + and state.has(SkillNames.base_skill_fitness, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_athlete_7A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) + and state.has(SkillNames.base_skill_fitness, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_athlete_8A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=3) + and state.has(SkillNames.base_skill_fitness, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_athlete_9A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=4) + and state.has(SkillNames.base_skill_fitness, player, count=7)) + set_rule(world.get_location(CareerNames.base_career_athlete_10A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) + and state.has(SkillNames.base_skill_fitness, player, count=8)) + set_rule(world.get_location(CareerNames.base_career_athlete_6B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=3) + and state.has(SkillNames.base_skill_fitness, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_athlete_7B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=3) + and state.has(SkillNames.base_skill_fitness, player, count=7)) + set_rule(world.get_location(CareerNames.base_career_athlete_8B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=4) + and state.has(SkillNames.base_skill_fitness, player, count=8)) + set_rule(world.get_location(CareerNames.base_career_athlete_9B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=5) + and state.has(SkillNames.base_skill_fitness, player, count=8)) + set_rule(world.get_location(CareerNames.base_career_athlete_10B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) + and state.has(SkillNames.base_skill_fitness, player, count=8)) + +def _career_astronaut(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_astronaut_4, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_astronaut_5, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=2) + and state.has(SkillNames.base_skill_fitness, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_astronaut_6, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=3) + and state.has(SkillNames.base_skill_fitness, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_astronaut_7, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=3) + and state.has(SkillNames.base_skill_fitness, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_astronaut_8A, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=4) + and state.has(SkillNames.base_skill_fitness, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_astronaut_8B, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=4) + and state.has(SkillNames.base_skill_fitness, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_astronaut_9A, player), + lambda state: state.has(SkillNames.base_skill_fitness, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_astronaut_10A, player), + lambda state: state.has(SkillNames.base_skill_rocket_science, player, count=2) + and state.has(SkillNames.base_skill_fitness, player, count=8)) + set_rule(world.get_location(CareerNames.base_career_astronaut_9B, player), + lambda state: state.has(SkillNames.base_skill_fitness, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_astronaut_10B, player), + lambda state: state.has(SkillNames.base_skill_rocket_science, player, count=2) + and state.has(SkillNames.base_skill_fitness, player, count=8)) + +def _career_business(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_business_5, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_business_6, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_business_7A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) + and state.has(SkillNames.base_skill_logic, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_business_7B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=2) + and state.has(SkillNames.base_skill_logic, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_business_8A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=4) + and state.has(SkillNames.base_skill_logic, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_business_9A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) + and state.has(SkillNames.base_skill_logic, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_business_10A, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=8) + and state.has(SkillNames.base_skill_logic, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_business_8B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=3) + and state.has(SkillNames.base_skill_logic, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_business_9B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=4) + and state.has(SkillNames.base_skill_logic, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_business_10B, player), + lambda state: state.has(SkillNames.base_skill_charisma, player, count=6) + and state.has(SkillNames.base_skill_logic, player, count=8)) + +def _career_criminal(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_criminal_4, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_criminal_5, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_criminal_6A, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_criminal_6B, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_criminal_7A, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_criminal_8A, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_criminal_9A, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=7) + and state.has(SkillNames.base_skill_handiness, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_criminal_10A, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=8) + and state.has(SkillNames.base_skill_handiness, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_criminal_7B, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=5) + and state.has(SkillNames.base_skill_programming, player, count=0)) + set_rule(world.get_location(CareerNames.base_career_criminal_8B, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=6) + and state.has(SkillNames.base_skill_programming, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_criminal_9B, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=7) + and state.has(SkillNames.base_skill_programming, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_criminal_10B, player), + lambda state: state.has(SkillNames.base_skill_mischief, player, count=8) + and state.has(SkillNames.base_skill_programming, player, count=6)) +def _career_culinary(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_culinary_5, player), + lambda state: state.has(SkillNames.base_skill_cooking, player, count=1) + and state.has(SkillNames.base_skill_mixology, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_culinary_6A, player), + lambda state: state.has(SkillNames.base_skill_cooking, player, count=2) + and state.has(SkillNames.base_skill_mixology, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_6B, player), + lambda state: state.has(SkillNames.base_skill_cooking, player, count=2) + and state.has(SkillNames.base_skill_mixology, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_7A, player), + lambda state: state.has(SkillNames.base_skill_cooking, player, count=4) + and state.has(SkillNames.base_skill_gourmet, player, count=0) + and state.has(SkillNames.base_skill_mixology, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_8A, player), + lambda state: state.has(SkillNames.base_skill_cooking, player, count=6) + and state.has(SkillNames.base_skill_gourmet, player, count=4) + and state.has(SkillNames.base_skill_mixology, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_9A, player), + lambda state: state.has(SkillNames.base_skill_cooking, player, count=6) + and state.has(SkillNames.base_skill_gourmet, player, count=4) + and state.has(SkillNames.base_skill_mixology, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_10A, player), + lambda state: state.has(SkillNames.base_skill_cooking, player, count=8) + and state.has(SkillNames.base_skill_gourmet, player, count=6) + and state.has(SkillNames.base_skill_mixology, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_7B, player), + lambda state: state.has(SkillNames.base_skill_mixology, player, count=3) + and state.has(SkillNames.base_skill_charisma, player, count=0) + and state.has(SkillNames.base_skill_cooking, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_8B, player), + lambda state: state.has(SkillNames.base_skill_mixology, player, count=5) + and state.has(SkillNames.base_skill_charisma, player, count=2) + and state.has(SkillNames.base_skill_cooking, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_9B, player), + lambda state: state.has(SkillNames.base_skill_mixology, player, count=6) + and state.has(SkillNames.base_skill_charisma, player, count=4) + and state.has(SkillNames.base_skill_cooking, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_culinary_10B, player), + lambda state: state.has(SkillNames.base_skill_mixology, player, count=8) + and state.has(SkillNames.base_skill_charisma, player, count=6) + and state.has(SkillNames.base_skill_cooking, player, count=2)) + +def _career_entertainer(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_entertainer_5A, player), + lambda state: (state.has(SkillNames.base_skill_guitar, player, count=1) + or state.has(SkillNames.base_skill_violin, player, count=1)) + and state.has(SkillNames.base_skill_comedy, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_entertainer_5B, player), + lambda state: (state.has(SkillNames.base_skill_guitar, player, count=1) + or state.has(SkillNames.base_skill_violin, player, count=1)) + and state.has(SkillNames.base_skill_comedy, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_entertainer_6A, player), + lambda state: state.has(SkillNames.base_skill_violin, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_entertainer_7A, player), + lambda state: (state.has(SkillNames.base_skill_guitar, player, count=3) + or state.has(SkillNames.base_skill_violin, player, count=3)) + and state.has(SkillNames.base_skill_piano, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_entertainer_8A, player), + lambda state: (state.has(SkillNames.base_skill_guitar, player, count=4) + or state.has(SkillNames.base_skill_violin, player, count=4)) + and state.has(SkillNames.base_skill_piano, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_entertainer_9A, player), + lambda state: (state.has(SkillNames.base_skill_guitar, player, count=5) + or state.has(SkillNames.base_skill_violin, player, count=5)) + and state.has(SkillNames.base_skill_piano, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_entertainer_10A, player), + lambda state: (state.has(SkillNames.base_skill_guitar, player, count=6) + or state.has(SkillNames.base_skill_violin, player, count=6)) + and state.has(SkillNames.base_skill_piano, player, count=8)) + set_rule(world.get_location(CareerNames.base_career_entertainer_6B, player), + lambda state: state.has(SkillNames.base_skill_comedy, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_entertainer_7B, player), + lambda state: state.has(SkillNames.base_skill_comedy, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_entertainer_8B, player), + lambda state: state.has(SkillNames.base_skill_comedy, player, count=6) + and state.has(SkillNames.base_skill_charisma, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_entertainer_9B, player), + lambda state: state.has(SkillNames.base_skill_comedy, player, count=7) + and state.has(SkillNames.base_skill_charisma, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_entertainer_10B, player), + lambda state: state.has(SkillNames.base_skill_comedy, player, count=8) + and state.has(SkillNames.base_skill_charisma, player, count=6)) + +def _career_painter(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_painter_4, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_painter_5, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_painter_6, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_painter_7A, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_painter_7B, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_painter_8A, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_painter_9A, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=7) + and state.has(SkillNames.base_skill_logic, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_painter_10A, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=8) + and state.has(SkillNames.base_skill_logic, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_painter_8B, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_painter_9B, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=7) + and state.has(SkillNames.base_skill_charisma, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_painter_10B, player), + lambda state: state.has(SkillNames.base_skill_painting, player, count=8) + and state.has(SkillNames.base_skill_charisma, player, count=4)) +def _career_secret_agent(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_secret_agent_4, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=1) + and state.has(SkillNames.base_skill_charisma, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_5, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=1) + and state.has(SkillNames.base_skill_charisma, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_6, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=3) + and state.has(SkillNames.base_skill_charisma, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_7, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=3) + and state.has(SkillNames.base_skill_charisma, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_8A, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=4) + and state.has(SkillNames.base_skill_charisma, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_8B, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=4) + and state.has(SkillNames.base_skill_charisma, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_9A, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=6) + and state.has(SkillNames.base_skill_charisma, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_10A, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=8) + and state.has(SkillNames.base_skill_charisma, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_9B, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_10B, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=8) + and state.has(SkillNames.base_skill_mischief, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_secret_agent_11B, player), + lambda state: state.has(SkillNames.base_skill_logic, player, count=8) + and state.has(SkillNames.base_skill_mischief, player, count=4)) +def _career_style_influencer(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_style_influencer_4, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_5, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_6A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=3) + and state.has(SkillNames.base_skill_charisma, player, count=1) + and state.has(SkillNames.base_skill_painting, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_7A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=4) + and state.has(SkillNames.base_skill_charisma, player, count=3) + and state.has(SkillNames.base_skill_painting, player, count=2) + and state.has(SkillNames.base_skill_photography, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_8A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=5) + and state.has(SkillNames.base_skill_charisma, player, count=4) + and state.has(SkillNames.base_skill_painting, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_9A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=6) + and state.has(SkillNames.base_skill_charisma, player, count=5) + and state.has(SkillNames.base_skill_painting, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_10A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=7) + and state.has(SkillNames.base_skill_charisma, player, count=6) + and state.has(SkillNames.base_skill_painting, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_6B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=3) + and state.has(SkillNames.base_skill_charisma, player, count=1) + and state.has(SkillNames.base_skill_painting, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_7B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=4) + and state.has(SkillNames.base_skill_charisma, player, count=3) + and state.has(SkillNames.base_skill_painting, player, count=2) + and state.has(SkillNames.base_skill_photography, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_8B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=5) + and state.has(SkillNames.base_skill_charisma, player, count=4) + and state.has(SkillNames.base_skill_painting, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_9B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=6) + and state.has(SkillNames.base_skill_charisma, player, count=5) + and state.has(SkillNames.base_skill_painting, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_style_influencer_10B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=7) + and state.has(SkillNames.base_skill_charisma, player, count=6) + and state.has(SkillNames.base_skill_painting, player, count=5)) +def _career_tech_guru(world: MultiWorld, player: int): + # TODO check project manager career logic https://discord.com/channels/731205301247803413/1079002955262480424/1403764728177758252 + set_rule(world.get_location(CareerNames.base_career_tech_guru_4, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 3)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_5, player), + lambda state: has_skill(state, SkillNames.base_skill_programming, player, 4) + and has_skill(state, SkillNames.base_skill_video_gaming, player, 3)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_6, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=3) + and state.has(SkillNames.base_skill_video_gaming, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_7A, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=4) + and state.has(SkillNames.base_skill_video_gaming, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_7B, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=4) + and state.has(SkillNames.base_skill_video_gaming, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_8A, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=4) + and state.has(SkillNames.base_skill_video_gaming, player, count=4)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_9A, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=5) + and state.has(SkillNames.base_skill_video_gaming, player, count=6)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_10A, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=6) + and state.has(SkillNames.base_skill_video_gaming, player, count=8)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_8B, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=6) + and state.has(SkillNames.base_skill_charisma, player, count=0)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_9B, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=7) + and state.has(SkillNames.base_skill_charisma, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_tech_guru_10B, player), + lambda state: state.has(SkillNames.base_skill_programming, player, count=8) + and state.has(SkillNames.base_skill_charisma, player, count=4)) +def _career_writer(world: MultiWorld, player: int): + set_rule(world.get_location(CareerNames.base_career_writer_4, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_writer_5, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_writer_6A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_writer_6B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_writer_7A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_writer_8A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=6) + and state.has(SkillNames.base_skill_logic, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_writer_9A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=7) + and state.has(SkillNames.base_skill_logic, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_writer_10A, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=8) + and state.has(SkillNames.base_skill_logic, player, count=3)) + set_rule(world.get_location(CareerNames.base_career_writer_7B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=5)) + set_rule(world.get_location(CareerNames.base_career_writer_8B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=6) + and state.has(SkillNames.base_skill_charisma, player, count=1)) + set_rule(world.get_location(CareerNames.base_career_writer_9B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=7) + and state.has(SkillNames.base_skill_charisma, player, count=2)) + set_rule(world.get_location(CareerNames.base_career_writer_10B, player), + lambda state: state.has(SkillNames.base_skill_writing, player, count=8) + and state.has(SkillNames.base_skill_charisma, player, count=3)) + +CAREER_RULES = { + CareerNames.base_career_athlete: _career_athlete, + CareerNames.base_career_astronaut: _career_astronaut, + CareerNames.base_career_business: _career_business, + CareerNames.base_career_criminal: _career_criminal, + CareerNames.base_career_culinary: _career_culinary, + CareerNames.base_career_entertainer: _career_entertainer, + CareerNames.base_career_painter: _career_painter, + CareerNames.base_career_secret_agent: _career_secret_agent, + CareerNames.base_career_style_influencer: _career_style_influencer, + CareerNames.base_career_tech_guru: _career_tech_guru, + CareerNames.base_career_writer: _career_writer, +} + +def set_career_rules(world: MultiWorld, player: int, options: Sims4Options): + career = options.career + + for career_name, handler in CAREER_RULES.items(): + if career_name in career: + handler(world, player) \ No newline at end of file From 4a48a54c05b4c0d51511bb60efac727315dc8c6a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:32:45 -0700 Subject: [PATCH 17/71] use the new structure --- worlds/sims4/Rules.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 6451d80eb12d..f00f69efc166 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -21,10 +21,8 @@ def _sims4_rule(self, player: int): def set_rules(world: MultiWorld, player: int, options: Sims4Options): # Career Rules - # TODO relearn how the career locations send, and then refactor this to use has_skill - - career = options.career + set_career_rules(world, player, options) # Part Time Jobs @@ -828,6 +826,7 @@ def _career_writer(world: MultiWorld, player: int): } def set_career_rules(world: MultiWorld, player: int, options: Sims4Options): + # TODO relearn how the career locations send, and then refactor this to use has_skill career = options.career for career_name, handler in CAREER_RULES.items(): From 3fb5ece82acd34d16d27110df6f0d3b0a5c2dc99 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:33:21 -0700 Subject: [PATCH 18/71] make the set rules function leaner --- worlds/sims4/Rules.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index f00f69efc166..6ed455475aba 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -20,19 +20,12 @@ def _sims4_rule(self, player: int): def set_rules(world: MultiWorld, player: int, options: Sims4Options): - # Career Rules - set_career_rules(world, player, options) - - # Part Time Jobs - - # Aspirations - set_aspiration_rules(world, player, options) - - # Skillchecks set_skill_rules(world, player, options) + # TODO: Part Time Jobs? + def count_skills_over(threshold: int, state, player) -> int: total_count = 0 From 99f3afce20ca776090e4a0310e6e1da41fbea510 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:33:41 -0700 Subject: [PATCH 19/71] okay this should be good now --- worlds/sims4/Rules.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 6ed455475aba..4e691d09ebca 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -19,13 +19,11 @@ def _sims4_rule(self, player: int): return True def set_rules(world: MultiWorld, player: int, options: Sims4Options): - + # TODO: Part Time Jobs? set_career_rules(world, player, options) set_aspiration_rules(world, player, options) set_skill_rules(world, player, options) - # TODO: Part Time Jobs? - def count_skills_over(threshold: int, state, player) -> int: total_count = 0 From d3ae8a997572e87a2a8547d6a5935554a686ed7a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:35:03 -0700 Subject: [PATCH 20/71] move the completion condition call over --- worlds/sims4/Rules.py | 2 +- worlds/sims4/__init__.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 4e691d09ebca..894a437aee01 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -23,7 +23,7 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): set_career_rules(world, player, options) set_aspiration_rules(world, player, options) set_skill_rules(world, player, options) - + set_completion_condition(world, player, options) def count_skills_over(threshold: int, state, player) -> int: total_count = 0 diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index fef69dec9c94..e5ad5cce642e 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -127,7 +127,6 @@ def create_regions(self): def set_rules(self) -> None: ts4_set_rules(self.multiworld, self.player, self.options) - set_completion_condition(self.multiworld, self.player, self.options) def fill_slot_data(self) -> Mapping[str, Any]: # slot_data = self.options.as_dict("goal", "career", "expansion_packs", "game_packs", "stuff_packs", "cas_kits", "build_kits") From cb6c2c065aca052f72eab656f2ee4f44b8ef6261 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:41:56 -0700 Subject: [PATCH 21/71] oops that was broken at runtime --- worlds/sims4/Rules.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 894a437aee01..d4d155e522ea 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -8,7 +8,7 @@ from ..generic.Rules import set_rule from .Names import SkillNames, CareerNames, AspirationNames -from .Options import Sims4Options +from .Options import AspirationGoal, Sims4Options if TYPE_CHECKING: from . import Sims4World @@ -390,23 +390,23 @@ def _neighborly_advisor(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) ASPIRATION_RULES = { - Sims4Options.goal.option_bodybuilder: _bodybuilder, - Sims4Options.goal.option_painter_extraordinaire: _painter_extraordinaire, - Sims4Options.goal.option_bestselling_author: _bestselling_author, - Sims4Options.goal.option_musical_genius: _musical_genius, - Sims4Options.goal.option_public_enemy: _public_enemy, - Sims4Options.goal.option_chief_of_mischief: _chief_of_mischief, - Sims4Options.goal.option_master_chef: _master_chef, - Sims4Options.goal.option_master_mixologist: _master_mixologist, - Sims4Options.goal.option_renaissance_sim: _renaissance_sim, - Sims4Options.goal.option_nerd_brain: _nerd_brain, - Sims4Options.goal.option_computer_whiz: _computer_whiz, - Sims4Options.goal.option_serial_romantic: _serial_romantic, - Sims4Options.goal.option_freelance_botanist: _freelance_botanist, - Sims4Options.goal.option_angling_ace: _angling_ace, - Sims4Options.goal.option_joke_star: _joke_star, - Sims4Options.goal.option_friend_of_the_world: _friend_of_the_world, - Sims4Options.goal.option_neighborly_advisor: _neighborly_advisor, + AspirationGoal.option_bodybuilder: _bodybuilder, + AspirationGoal.option_painter_extraordinaire: _painter_extraordinaire, + AspirationGoal.option_bestselling_author: _bestselling_author, + AspirationGoal.option_musical_genius: _musical_genius, + AspirationGoal.option_public_enemy: _public_enemy, + AspirationGoal.option_chief_of_mischief: _chief_of_mischief, + AspirationGoal.option_master_chef: _master_chef, + AspirationGoal.option_master_mixologist: _master_mixologist, + AspirationGoal.option_renaissance_sim: _renaissance_sim, + AspirationGoal.option_nerd_brain: _nerd_brain, + AspirationGoal.option_computer_whiz: _computer_whiz, + AspirationGoal.option_serial_romantic: _serial_romantic, + AspirationGoal.option_freelance_botanist: _freelance_botanist, + AspirationGoal.option_angling_ace: _angling_ace, + AspirationGoal.option_joke_star: _joke_star, + AspirationGoal.option_friend_of_the_world: _friend_of_the_world, + AspirationGoal.option_neighborly_advisor: _neighborly_advisor, } def set_aspiration_rules(world: MultiWorld, player: int, options: Sims4Options): From fa3e777dd9fb5087bf88fed32551b9eec6714563 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:55:27 -0700 Subject: [PATCH 22/71] move the helper functions down in order to make it easier to edit them --- worlds/sims4/Rules.py | 111 +++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index d4d155e522ea..b0fe1fc286d7 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -25,60 +25,6 @@ def set_rules(world: MultiWorld, player: int, options: Sims4Options): set_skill_rules(world, player, options) set_completion_condition(world, player, options) -def count_skills_over(threshold: int, state, player) -> int: - total_count = 0 - - if state.has(SkillNames.base_skill_charisma, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_fitness, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_mischief, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_logic, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_cooking, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_mixology, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_comedy, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_writing, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_fishing, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_gardening, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_video_gaming, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_programming, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_photography, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_handiness, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_piano, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_violin, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_guitar, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_painting, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_rocket_science, player, count=threshold): - total_count += 1 - if state.has(SkillNames.base_skill_gourmet, player, count=threshold): - total_count += 1 - - return total_count - -def has_skill(state: CollectionState, skill: str, player: int, skill_level: int) -> bool: - # determines how many skill items are required based on the skill level passed into the function - skills_required: int = skill_level - 2 - return state.has(skill, player, skills_required) -def has_multiple_skills(state: CollectionState, skills_and_levels: dict[str, int], player: int): - skills = list(skills_and_levels.keys()) - return has_skill(state, skills[0], player, skills_and_levels[skills[0]]) and has_skill(state, skills[1], player, skills_and_levels[skills[1]]) - # TODO: use events for the completion condition in order to facilitate easier goal stuff, and presence in spoiler (also permits future goals to be more dynamic) def set_completion_condition(world: MultiWorld, player: int, options: Sims4Options): goal = options.goal @@ -822,4 +768,59 @@ def set_career_rules(world: MultiWorld, player: int, options: Sims4Options): for career_name, handler in CAREER_RULES.items(): if career_name in career: - handler(world, player) \ No newline at end of file + handler(world, player) + +def count_skills_over(threshold: int, state, player) -> int: + total_count = 0 + + if state.has(SkillNames.base_skill_charisma, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_fitness, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_mischief, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_logic, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_cooking, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_mixology, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_comedy, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_writing, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_fishing, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_gardening, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_video_gaming, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_programming, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_photography, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_handiness, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_piano, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_violin, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_guitar, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_painting, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_rocket_science, player, count=threshold): + total_count += 1 + if state.has(SkillNames.base_skill_gourmet, player, count=threshold): + total_count += 1 + + return total_count + +def has_skill(state: CollectionState, skill: str, player: int, skill_level: int) -> bool: + # determines how many skill items are required based on the skill level passed into the function + skills_required: int = skill_level - 2 + return state.has(skill, player, skills_required) + +def has_multiple_skills(state: CollectionState, skills_and_levels: dict[str, int], player: int): + skills = list(skills_and_levels.keys()) + return has_skill(state, skills[0], player, skills_and_levels[skills[0]]) and has_skill(state, skills[1], player, skills_and_levels[skills[1]]) \ No newline at end of file From d6cf72e73ef38832492ff7d56f910f587352de1a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:56:19 -0700 Subject: [PATCH 23/71] remove the old import --- worlds/sims4/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index e5ad5cce642e..3f158a4c4f83 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -12,7 +12,7 @@ from .Options import Sims4Options from .Regions import sims4_careers, sims4_aspiration_milestones, sims4_skill_dependencies, \ sims4_regions -from .Rules import set_completion_condition, set_rules as ts4_set_rules +from .Rules import set_rules as ts4_set_rules from .Groups import location_name_groups, item_name_groups from .UT import UTMixin from .Settings import Sims4Settings From d6fd1eb8502229736155ec57d89330b76a717a2f Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 12:56:44 -0700 Subject: [PATCH 24/71] rename the import --- worlds/sims4/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 3f158a4c4f83..7f4cc48e0ba9 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -12,7 +12,7 @@ from .Options import Sims4Options from .Regions import sims4_careers, sims4_aspiration_milestones, sims4_skill_dependencies, \ sims4_regions -from .Rules import set_rules as ts4_set_rules +from .Rules import set_rules from .Groups import location_name_groups, item_name_groups from .UT import UTMixin from .Settings import Sims4Settings @@ -126,7 +126,7 @@ def create_regions(self): self.multiworld.regions.append(menu) def set_rules(self) -> None: - ts4_set_rules(self.multiworld, self.player, self.options) + set_rules(self.multiworld, self.player, self.options) def fill_slot_data(self) -> Mapping[str, Any]: # slot_data = self.options.as_dict("goal", "career", "expansion_packs", "game_packs", "stuff_packs", "cas_kits", "build_kits") From 620b265f218e4d71472fa3151a7dacefcdba29ff Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:11:37 -0700 Subject: [PATCH 25/71] let's not override the location constructor --- worlds/sims4/Locations.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/worlds/sims4/Locations.py b/worlds/sims4/Locations.py index 66097397a37e..841bfb27eb43 100644 --- a/worlds/sims4/Locations.py +++ b/worlds/sims4/Locations.py @@ -9,10 +9,6 @@ class Sims4Location(Location): game: str = "The Sims 4" - def __init__(self, player: int, name: str, address: Optional[int], parent): - super().__init__(player, name, address, parent) - self.event = not address - class Sims4LocationDict(TypedDict, total=False): name: str From 5b22429a5bff169aef160ee9b7622f39d46419d7 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:12:02 -0700 Subject: [PATCH 26/71] add an event location creator method --- worlds/sims4/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 7f4cc48e0ba9..a2ae34accf84 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -73,6 +73,9 @@ def create_item(self, name: str) -> Item: def create_event(self, event: str): return Sims4Item(event, ItemClassification.progression, None, self.player) + def create_event_location(self, event: str): + return Sims4Location(self.player, event, None) + def create_items(self) -> None: used_dlc = set(self.options.expansion_packs.value | self.options.game_packs.value | self.options.stuff_packs.value) pool = [] From 7d0db304f218c555788fb0a1c842a8a68a9adf58 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:24:32 -0700 Subject: [PATCH 27/71] start working on events --- worlds/sims4/Rules.py | 2 ++ worlds/sims4/__init__.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index b0fe1fc286d7..6a33e60dca4c 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -189,6 +189,8 @@ def _bodybuilder(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) + set_rule(world.get_location("Completed Bodybuilder Aspiration", player), + lambda state: state.can_reach(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), player=player)) def _painter_extraordinaire(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_fine_artist, player), diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index a2ae34accf84..85bd70dc8255 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -126,6 +126,11 @@ def create_regions(self): menu.locations.append( Sims4Location(self.player, skill_name, self.location_name_to_id.get(skill_name), menu) ) + if aspiration_key == self.options.goal.option_bodybuilder: + event = self.create_event_location("Completed Bodybuilder Aspiration") + menu.locations.append(event) + event.place_locked_item(self.create_event("Completed Bodybuilder")) + self.multiworld.regions.append(menu) def set_rules(self) -> None: From b54b840c1d67249cc1265f1d7714248088d6223e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:28:14 -0700 Subject: [PATCH 28/71] okay i think this is the first event --- worlds/sims4/Names/EventNames.py | 2 ++ worlds/sims4/Rules.py | 7 +++---- worlds/sims4/__init__.py | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 worlds/sims4/Names/EventNames.py diff --git a/worlds/sims4/Names/EventNames.py b/worlds/sims4/Names/EventNames.py new file mode 100644 index 000000000000..d27e3ef7ef8e --- /dev/null +++ b/worlds/sims4/Names/EventNames.py @@ -0,0 +1,2 @@ +bodybuilder = "Completed Bodybuilder Aspiration" +bodybuilder_item = "Completed Bodybuilder" \ No newline at end of file diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 6a33e60dca4c..8203888f12ff 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -7,7 +7,7 @@ from .Names.DLC import ExpansionNames, GamePackNames, StuffNames from ..generic.Rules import set_rule -from .Names import SkillNames, CareerNames, AspirationNames +from .Names import EventNames, SkillNames, CareerNames, AspirationNames from .Options import AspirationGoal, Sims4Options if TYPE_CHECKING: @@ -31,8 +31,7 @@ def set_completion_condition(world: MultiWorld, player: int, options: Sims4Optio goal_value = goal.value if goal_value == goal.option_bodybuilder: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_bodybuilder, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.bodybuilder_item, player) elif goal_value == goal.option_painter_extraordinaire: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), player=player) @@ -189,7 +188,7 @@ def _bodybuilder(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), lambda state: has_skill(state, SkillNames.base_skill_fitness, player, 10)) - set_rule(world.get_location("Completed Bodybuilder Aspiration", player), + set_rule(world.get_location(EventNames.bodybuilder, player), lambda state: state.can_reach(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), player=player)) def _painter_extraordinaire(world: MultiWorld, player: int): diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 85bd70dc8255..57d6eba374ca 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -4,6 +4,7 @@ # ap imports from BaseClasses import Item, ItemClassification, Region, Entrance from worlds.AutoWorld import World +from .Names import EventNames from ..LauncherComponents import Component, components, Type, icon_paths, launch # TS4 specific imports @@ -127,9 +128,9 @@ def create_regions(self): Sims4Location(self.player, skill_name, self.location_name_to_id.get(skill_name), menu) ) if aspiration_key == self.options.goal.option_bodybuilder: - event = self.create_event_location("Completed Bodybuilder Aspiration") + event = self.create_event_location(EventNames.bodybuilder) menu.locations.append(event) - event.place_locked_item(self.create_event("Completed Bodybuilder")) + event.place_locked_item(self.create_event(EventNames.bodybuilder_item)) self.multiworld.regions.append(menu) From c9f8c14c8ef59ac0ab5d975166fb40e678896a97 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:28:50 -0700 Subject: [PATCH 29/71] move the import --- worlds/sims4/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 57d6eba374ca..af8cc6d54c38 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -4,12 +4,12 @@ # ap imports from BaseClasses import Item, ItemClassification, Region, Entrance from worlds.AutoWorld import World -from .Names import EventNames from ..LauncherComponents import Component, components, Type, icon_paths, launch # TS4 specific imports from .Locations import location_table, Sims4Location, skill_locations_table from .Items import item_table, skills_table, Sims4Item, junk_table, filler_set +from .Names import EventNames from .Options import Sims4Options from .Regions import sims4_careers, sims4_aspiration_milestones, sims4_skill_dependencies, \ sims4_regions From af0a1ed148330edd7b3d28b4566f2305f4a48c70 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:33:03 -0700 Subject: [PATCH 30/71] change it back? --- worlds/sims4/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index af8cc6d54c38..63101642b5ca 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -131,6 +131,10 @@ def create_regions(self): event = self.create_event_location(EventNames.bodybuilder) menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.bodybuilder_item)) + elif aspiration_key == self.options.goal.option_painter_extraordinaire: + event = self.create_event_location(EventNames.painter_extraordinaire) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.painter_extraordinaire_item)) self.multiworld.regions.append(menu) From af431c113a6b2618399f8ac194e712a70e929cea Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:33:42 -0700 Subject: [PATCH 31/71] change it back? --- worlds/sims4/Locations.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worlds/sims4/Locations.py b/worlds/sims4/Locations.py index 841bfb27eb43..66097397a37e 100644 --- a/worlds/sims4/Locations.py +++ b/worlds/sims4/Locations.py @@ -9,6 +9,10 @@ class Sims4Location(Location): game: str = "The Sims 4" + def __init__(self, player: int, name: str, address: Optional[int], parent): + super().__init__(player, name, address, parent) + self.event = not address + class Sims4LocationDict(TypedDict, total=False): name: str From ceb584d9cb8642728b957122e4230f58566bdc1e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:33:50 -0700 Subject: [PATCH 32/71] another one --- worlds/sims4/Names/EventNames.py | 4 +++- worlds/sims4/Rules.py | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/worlds/sims4/Names/EventNames.py b/worlds/sims4/Names/EventNames.py index d27e3ef7ef8e..f07ba373387c 100644 --- a/worlds/sims4/Names/EventNames.py +++ b/worlds/sims4/Names/EventNames.py @@ -1,2 +1,4 @@ bodybuilder = "Completed Bodybuilder Aspiration" -bodybuilder_item = "Completed Bodybuilder" \ No newline at end of file +bodybuilder_item = "Completed Bodybuilder" +painter_extraordinaire = "Completed Painter Extraordinaire Aspiration" +painter_extraordinaire_item = "Completed Painter Extraordinaire" \ No newline at end of file diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 8203888f12ff..296fb804db50 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -33,8 +33,7 @@ def set_completion_condition(world: MultiWorld, player: int, options: Sims4Optio if goal_value == goal.option_bodybuilder: world.completion_condition[player] = lambda state: state.has(EventNames.bodybuilder_item, player) elif goal_value == goal.option_painter_extraordinaire: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.painter_extraordinaire_item, player) elif goal_value == goal.option_bestselling_author: world.completion_condition[player] = lambda state: state.can_reach( world.get_location(AspirationNames.base_aspiration_bestselling_author, player), player=player) @@ -198,6 +197,9 @@ def _painter_extraordinaire(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_painting, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) + set_rule(world.get_location(EventNames.painter_extraordinaire, player), + lambda state: state.can_reach(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), + player=player)) def _bestselling_author(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_competent_wordsmith, player), From 4306120e09930e3ba6bf8bc39c9167264bc05fb9 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:35:27 -0700 Subject: [PATCH 33/71] oooooooops --- worlds/sims4/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 63101642b5ca..79101d827299 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -111,7 +111,8 @@ def create_region(self, name: str, locations=None, exits=None): def create_regions(self): menu = self.create_region("Menu", locations=None, exits=None) chosen_careers = sorted(self.options.career.value) - aspiration_key = self.options.goal.current_key + goal = self.options.goal + aspiration_key = goal.current_key for career_key in chosen_careers: for career in sims4_careers[career_key.lower().replace(" ", "_")]: menu.locations.append( @@ -127,11 +128,11 @@ def create_regions(self): menu.locations.append( Sims4Location(self.player, skill_name, self.location_name_to_id.get(skill_name), menu) ) - if aspiration_key == self.options.goal.option_bodybuilder: + if goal.value == goal.option_bodybuilder: event = self.create_event_location(EventNames.bodybuilder) menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.bodybuilder_item)) - elif aspiration_key == self.options.goal.option_painter_extraordinaire: + elif goal.value == goal.option_painter_extraordinaire: event = self.create_event_location(EventNames.painter_extraordinaire) menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.painter_extraordinaire_item)) From 26a0bfbc516ef45c068487e86e87f54ae0fbab08 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 13:44:46 -0700 Subject: [PATCH 34/71] okay well that was a fucking shitshow --- worlds/sims4/Rules.py | 2 +- worlds/sims4/__init__.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 296fb804db50..6d69b9422fdb 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -198,7 +198,7 @@ def _painter_extraordinaire(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), lambda state: has_skill(state, SkillNames.base_skill_painting, player, 10)) set_rule(world.get_location(EventNames.painter_extraordinaire, player), - lambda state: state.can_reach(world.get_location(AspirationNames.base_aspiration_bodybuilder, player), + lambda state: state.can_reach(world.get_location(AspirationNames.base_aspiration_painter_extraordinaire, player), player=player)) def _bestselling_author(world: MultiWorld, player: int): diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 79101d827299..0b71a0563aed 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -74,8 +74,8 @@ def create_item(self, name: str) -> Item: def create_event(self, event: str): return Sims4Item(event, ItemClassification.progression, None, self.player) - def create_event_location(self, event: str): - return Sims4Location(self.player, event, None) + def create_event_location(self, event: str, region: Region): + return Sims4Location(self.player, event, None, region) def create_items(self) -> None: used_dlc = set(self.options.expansion_packs.value | self.options.game_packs.value | self.options.stuff_packs.value) @@ -129,11 +129,11 @@ def create_regions(self): Sims4Location(self.player, skill_name, self.location_name_to_id.get(skill_name), menu) ) if goal.value == goal.option_bodybuilder: - event = self.create_event_location(EventNames.bodybuilder) + event = self.create_event_location(EventNames.bodybuilder, menu) menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.bodybuilder_item)) elif goal.value == goal.option_painter_extraordinaire: - event = self.create_event_location(EventNames.painter_extraordinaire) + event = self.create_event_location(EventNames.painter_extraordinaire, menu) menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.painter_extraordinaire_item)) From 55ae9a919dbe936f1f1829e524f4ac8268151492 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 15:37:30 -0700 Subject: [PATCH 35/71] okay we're fully migrated to events for the goal now --- worlds/sims4/Names/EventNames.py | 34 +++++++++++- worlds/sims4/Rules.py | 94 +++++++++++++++++++++----------- worlds/sims4/__init__.py | 65 +++++++++++++++++++++- 3 files changed, 158 insertions(+), 35 deletions(-) diff --git a/worlds/sims4/Names/EventNames.py b/worlds/sims4/Names/EventNames.py index f07ba373387c..640fbb0dfeef 100644 --- a/worlds/sims4/Names/EventNames.py +++ b/worlds/sims4/Names/EventNames.py @@ -1,4 +1,36 @@ bodybuilder = "Completed Bodybuilder Aspiration" bodybuilder_item = "Completed Bodybuilder" painter_extraordinaire = "Completed Painter Extraordinaire Aspiration" -painter_extraordinaire_item = "Completed Painter Extraordinaire" \ No newline at end of file +painter_extraordinaire_item = "Completed Painter Extraordinaire" +bestselling_author = "Completed Bestselling Author Aspiration" +bestselling_author_item = "Completed Bestselling Author" +musical_genius = "Completed Musical Genius Aspiration" +musical_genius_item = "Completed Musical Genius" +chief_of_mischief = "Completed Chief of Mischief Aspiration" +chief_of_mischief_item = "Completed Chief of Mischief" +public_enemy = "Completed Public Enemy Aspiration" +public_enemy_item = "Completed Public Enemy" +master_chef = "Completed Master Chef Aspiration" +master_chef_item = "Completed Master Chef" +master_mixologist = "Completed Master Mixologist Aspiration" +master_mixologist_item = "Completed Master Mixologist" +renaissance_sim = "Completed Renaissance Sim Aspiration" +renaissance_sim_item = "Completed Renaissance Sim" +nerd_brain = "Completed Nerd Brain Aspiration" +nerd_brain_item = "Completed Nerd Brain" +computer_whiz = "Completed Computer Whiz Aspiration" +computer_whiz_item = "Completed Computer Whiz" +serial_romantic = "Completed Serial Romantic Aspiration" +serial_romantic_item = "Completed Serial Romantic" +freelance_botanist = "Completed Freelance Botanist Aspiration" +freelance_botanist_item = "Completed Freelance Botanist" +the_curator = "Completed The Curator Aspiration" +the_curator_item = "Completed The Curator" +angling_ace = "Completed Angling Ace Aspiration" +angling_ace_item = "Completed Angling Ace" +joke_star = "Completed Joke Star Aspiration" +joke_star_item = "Completed Joke Star" +friend_of_the_world = "Completed Friend of the World Aspiration" +friend_of_the_world_item = "Completed Friend of the World" +neighborly_advisor = "Completed Neighborly Advisor Aspiration" +neighborly_advisor_item = "Completed Neighborly Advisor" \ No newline at end of file diff --git a/worlds/sims4/Rules.py b/worlds/sims4/Rules.py index 6d69b9422fdb..c4ecc654f8f3 100644 --- a/worlds/sims4/Rules.py +++ b/worlds/sims4/Rules.py @@ -35,53 +35,37 @@ def set_completion_condition(world: MultiWorld, player: int, options: Sims4Optio elif goal_value == goal.option_painter_extraordinaire: world.completion_condition[player] = lambda state: state.has(EventNames.painter_extraordinaire_item, player) elif goal_value == goal.option_bestselling_author: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_bestselling_author, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.bestselling_author_item, player) elif goal_value == goal.option_musical_genius: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_musical_genius, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.musical_genius_item, player) elif goal_value == goal.option_public_enemy: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_public_enemy, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.public_enemy_item, player) elif goal_value == goal.option_chief_of_mischief: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.chief_of_mischief_item, player) elif goal_value == goal.option_master_chef: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_master_chef, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.master_chef_item, player) elif goal_value == goal.option_master_mixologist: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_master_mixologist, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.master_mixologist_item, player) elif goal_value == goal.option_renaissance_sim: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.renaissance_sim_item, player) elif goal_value == goal.option_nerd_brain: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_nerd_brain, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.nerd_brain_item, player) elif goal_value == goal.option_computer_whiz: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_computer_whiz, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.computer_whiz_item, player) elif goal_value == goal.option_serial_romantic: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_serial_romantic, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.serial_romantic_item, player) elif goal_value == goal.option_freelance_botanist: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.freelance_botanist_item, player) elif goal_value == goal.option_the_curator: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_the_curator, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.the_curator_item, player) elif goal_value == goal.option_angling_ace: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_angling_ace, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.angling_ace_item, player) elif goal_value == goal.option_joke_star: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_joke_star, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.joke_star_item, player) elif goal_value == goal.option_friend_of_the_world: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.friend_of_the_world_item, player) elif goal_value == goal.option_neighborly_advisor: - world.completion_condition[player] = lambda state: state.can_reach( - world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), player=player) + world.completion_condition[player] = lambda state: state.has(EventNames.neighborly_advisor_item, player) def set_skill_rules(world: MultiWorld, player: int, options: Sims4Options): skills = { @@ -208,6 +192,10 @@ def _bestselling_author(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_writing, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_bestselling_author, player), lambda state: has_skill(state, SkillNames.base_skill_writing, player, 10)) + set_rule(world.get_location(EventNames.bestselling_author, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_bestselling_author, player), player=player)) + def _musical_genius(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_fine_tuned, player), lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 4) @@ -221,6 +209,9 @@ def _musical_genius(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_guitar, player, 10) or has_skill(state, SkillNames.base_skill_violin, player, 10) or has_skill(state, SkillNames.base_skill_piano, player, 10)) + set_rule(world.get_location(EventNames.musical_genius, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_musical_genius, player), player=player)) def _public_enemy(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_criminal_mind, player), @@ -228,6 +219,9 @@ def _public_enemy(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_public_enemy, player), lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 8) and has_skill(state, SkillNames.base_skill_programming, player, 4)) + set_rule(world.get_location(EventNames.public_enemy, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_public_enemy, player), player=player)) def _chief_of_mischief(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_artful_trickster, player), @@ -236,6 +230,9 @@ def _chief_of_mischief(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), lambda state: has_skill(state, SkillNames.base_skill_mischief, player, 10)) + set_rule(world.get_location(EventNames.chief_of_mischief, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_chief_of_mischief, player), player=player)) def _master_chef(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_captain_cook, player), @@ -248,6 +245,9 @@ def _master_chef(world: MultiWorld, player: int): or (has_skill(state, SkillNames.base_skill_gourmet, player, 5) and has_skill(state, SkillNames.base_skill_mixology, player, 7) and has_skill(state, SkillNames.base_skill_charisma, player, 4))) + set_rule(world.get_location(EventNames.master_chef, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_master_chef, player), player=player)) def _master_mixologist(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_electric_mixer, player), @@ -258,6 +258,9 @@ def _master_mixologist(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_master_mixologist, player), lambda state: has_skill(state, SkillNames.base_skill_mixology, player, 10) and has_skill(state, SkillNames.base_skill_cooking, player, 4)) + set_rule(world.get_location(EventNames.master_mixologist, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_master_mixologist, player), player=player)) def _renaissance_sim(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), lambda state: state.has(SkillNames.base_skill_logic, player, count=1)) @@ -267,6 +270,9 @@ def _renaissance_sim(world: MultiWorld, player: int): lambda state: count_skills_over(3, state, player) >= 5) set_rule(world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), lambda state: count_skills_over(6, state, player) >= 6) + set_rule(world.get_location(EventNames.renaissance_sim, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_renaissance_sim, player), player=player)) def _nerd_brain(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_prudent_student, player), @@ -278,6 +284,9 @@ def _nerd_brain(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_nerd_brain, player), lambda state: has_skill(state, SkillNames.base_skill_logic, player, 10) and has_skill(state, SkillNames.base_skill_handiness, player, 5)) + set_rule(world.get_location(EventNames.nerd_brain, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_nerd_brain, player), player=player)) def _computer_whiz(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_technically_adept, player), @@ -287,6 +296,9 @@ def _computer_whiz(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_computer_whiz, player), lambda state: has_skill(state, SkillNames.base_skill_programming, player, 7) and has_skill(state, SkillNames.base_skill_video_gaming, player, 4)) + set_rule(world.get_location(EventNames.computer_whiz, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_computer_whiz, player), player=player)) def _serial_romantic(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_up_to_date, player), @@ -295,6 +307,9 @@ def _serial_romantic(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_serial_romantic, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) + set_rule(world.get_location(EventNames.serial_romantic, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_serial_romantic, player), player=player)) def _freelance_botanist (world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_garden_variety, player), @@ -303,6 +318,9 @@ def _freelance_botanist (world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), lambda state: has_skill(state, SkillNames.base_skill_gardening, player, 10)) + set_rule(world.get_location(EventNames.freelance_botanist, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_freelance_botanist, player), player=player)) def _angling_ace(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_hooked, player), @@ -311,6 +329,9 @@ def _angling_ace(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_angling_ace, player), lambda state: has_skill(state, SkillNames.base_skill_fishing, player, 10)) + set_rule(world.get_location(EventNames.angling_ace, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_angling_ace, player), player=player)) def _joke_star(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_practical_joker, player), @@ -325,6 +346,9 @@ def _joke_star(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_comedy, player, 10) and (has_skill(state, SkillNames.base_skill_guitar, player, 3) or has_skill(state, SkillNames.base_skill_violin, player, 3))) + set_rule(world.get_location(EventNames.joke_star, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_joke_star, player), player=player)) def _friend_of_the_world(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_well_liked, player), @@ -333,10 +357,16 @@ def _friend_of_the_world(world: MultiWorld, player: int): lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 6)) set_rule(world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 10)) + set_rule(world.get_location(EventNames.friend_of_the_world, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_friend_of_the_world, player), player=player)) def _neighborly_advisor(world: MultiWorld, player: int): set_rule(world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), lambda state: has_skill(state, SkillNames.base_skill_charisma, player, 7)) + set_rule(world.get_location(EventNames.neighborly_advisor, player), + lambda state: state.can_reach( + world.get_location(AspirationNames.base_aspiration_neighborly_advisor, player), player=player)) ASPIRATION_RULES = { AspirationGoal.option_bodybuilder: _bodybuilder, diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 0b71a0563aed..3be33041f506 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -112,6 +112,7 @@ def create_regions(self): menu = self.create_region("Menu", locations=None, exits=None) chosen_careers = sorted(self.options.career.value) goal = self.options.goal + goal_value = goal.value aspiration_key = goal.current_key for career_key in chosen_careers: for career in sims4_careers[career_key.lower().replace(" ", "_")]: @@ -128,14 +129,74 @@ def create_regions(self): menu.locations.append( Sims4Location(self.player, skill_name, self.location_name_to_id.get(skill_name), menu) ) - if goal.value == goal.option_bodybuilder: + if goal_value == goal.option_bodybuilder: event = self.create_event_location(EventNames.bodybuilder, menu) menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.bodybuilder_item)) - elif goal.value == goal.option_painter_extraordinaire: + elif goal_value == goal.option_painter_extraordinaire: event = self.create_event_location(EventNames.painter_extraordinaire, menu) menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.painter_extraordinaire_item)) + elif goal_value == goal.option_bestselling_author: + event = self.create_event_location(EventNames.bestselling_author, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.bestselling_author_item)) + elif goal_value == goal.option_musical_genius: + event = self.create_event_location(EventNames.musical_genius, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.musical_genius_item)) + elif goal_value == goal.option_public_enemy: + event = self.create_event_location(EventNames.public_enemy, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.public_enemy_item)) + elif goal_value == goal.option_chief_of_mischief: + event = self.create_event_location(EventNames.chief_of_mischief, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.chief_of_mischief_item)) + elif goal_value == goal.option_master_chef: + event = self.create_event_location(EventNames.master_mixologist, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.master_mixologist_item)) + elif goal_value == goal.option_renaissance_sim: + event = self.create_event_location(EventNames.renaissance_sim, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.renaissance_sim_item)) + elif goal_value == goal.option_nerd_brain: + event = self.create_event_location(EventNames.nerd_brain, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.nerd_brain_item)) + elif goal_value == goal.option_computer_whiz: + event = self.create_event_location(EventNames.computer_whiz, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.computer_whiz_item)) + elif goal_value == goal.option_serial_romantic: + event = self.create_event_location(EventNames.serial_romantic, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.serial_romantic_item)) + elif goal_value == goal.option_freelance_botanist: + event = self.create_event_location(EventNames.freelance_botanist, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.freelance_botanist_item)) + elif goal_value == goal.option_the_curator: + event = self.create_event_location(EventNames.the_curator, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.the_curator_item)) + elif goal_value == goal.option_angling_ace: + event = self.create_event_location(EventNames.angling_ace, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.angling_ace_item)) + elif goal_value == goal.option_joke_star: + event = self.create_event_location(EventNames.joke_star, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.joke_star_item)) + elif goal_value == goal.option_friend_of_the_world: + event = self.create_event_location(EventNames.friend_of_the_world, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.friend_of_the_world_item)) + elif goal_value == goal.option_neighborly_advisor: + event = self.create_event_location(EventNames.neighborly_advisor, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.neighborly_advisor_item)) self.multiworld.regions.append(menu) From dcce5198304528d5372846ef7202178d186307d3 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:00:36 -0700 Subject: [PATCH 36/71] fix the c&p mistake --- worlds/sims4/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 3be33041f506..7f51505d69d0 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -154,6 +154,10 @@ def create_regions(self): menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.chief_of_mischief_item)) elif goal_value == goal.option_master_chef: + event = self.create_event_location(EventNames.master_chef, menu) + menu.locations.append(event) + event.place_locked_item(self.create_event(EventNames.master_chef_item)) + elif goal_value == goal.option_master_mixologist: event = self.create_event_location(EventNames.master_mixologist, menu) menu.locations.append(event) event.place_locked_item(self.create_event(EventNames.master_mixologist_item)) From c44aa8d359026ffb580285626d5ef7b569336996 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:01:01 -0700 Subject: [PATCH 37/71] remove old code --- worlds/sims4/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 7f51505d69d0..d1e1af15d11e 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -56,9 +56,6 @@ class Sims4World(World, UTMixin): settings: ClassVar[Sims4Settings] - # ut_can_gen_without_yaml = True - # passthrough: dict[str, Any] - def generate_early(self) -> None: # this is specific to UT, it doesn't apply unless UT is being used self.get_options_from_slot_data(self) From ab74d9aed087dcd4dc610ab1ec39bd70e373f2e6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:01:19 -0700 Subject: [PATCH 38/71] new line for EOF --- worlds/sims4/Names/EventNames.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/Names/EventNames.py b/worlds/sims4/Names/EventNames.py index 640fbb0dfeef..6b319ffd53b0 100644 --- a/worlds/sims4/Names/EventNames.py +++ b/worlds/sims4/Names/EventNames.py @@ -33,4 +33,4 @@ friend_of_the_world = "Completed Friend of the World Aspiration" friend_of_the_world_item = "Completed Friend of the World" neighborly_advisor = "Completed Neighborly Advisor Aspiration" -neighborly_advisor_item = "Completed Neighborly Advisor" \ No newline at end of file +neighborly_advisor_item = "Completed Neighborly Advisor" From eaf003b4bf0251ece499ce1ac86cf280ec4f0b59 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:09:46 -0700 Subject: [PATCH 39/71] use a lookup table --- worlds/sims4/__init__.py | 97 +++++++++++----------------------------- 1 file changed, 26 insertions(+), 71 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index d1e1af15d11e..c9a839260916 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -56,6 +56,27 @@ class Sims4World(World, UTMixin): settings: ClassVar[Sims4Settings] + GOAL_TO_EVENT_MAPPING = { + Sims4Options.goal.option_bodybuilder: (EventNames.bodybuilder, EventNames.bodybuilder_item), + Sims4Options.goal.option_painter_extraordinaire: (EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item) + Sims4Options.goal.option_bestselling_author: (EventNames.bestselling_author, EventNames.bestselling_author_item) + Sims4Options.goal.option_musical_genius: (EventNames.musical_genius, EventNames.musical_genius_item), + Sims4Options.goal.option_public_enemy: (EventNames.public_enemy, EventNames.public_enemy_item), + Sims4Options.goal.option_chief_of_mischief: (EventNames.chief_of_mischief, EventNames.chief_of_mischief_item), + Sims4Options.goal.option_master_chef: (EventNames.master_chef, EventNames.master_chef_item), + Sims4Options.goal.option_master_mixologist: (EventNames.master_mixologist, EventNames.master_mixologist_item), + Sims4Options.goal.option_renaissance_sim: (EventNames.renaissance_sim, EventNames.renaissance_sim_item), + Sims4Options.goal.option_nerd_brain: (EventNames.nerd_brain, EventNames.nerd_brain_item), + Sims4Options.goal.option_computer_whiz: (EventNames.computer_whiz, EventNames.computer_whiz_item), + Sims4Options.goal.option_serial_romantic: (EventNames.serial_romantic, EventNames.serial_romantic_item), + Sims4Options.goal.option_freelance_botanist: (EventNames.freelance_botanist, EventNames.freelance_botanist_item), + Sims4Options.goal.option_the_curator: (EventNames.the_curator, EventNames.the_curator_item), + Sims4Options.goal.option_angling_ace: (EventNames.angling_ace, EventNames.angling_ace_item), + Sims4Options.goal.option_joke_star: (EventNames.joke_star, EventNames.joke_star_item), + Sims4Options.goal.option_friend_of_the_world: (EventNames.friend_of_the_world, EventNames.friend_of_the_world_item), + Sims4Options.goal.option_neighborly_advisor: (EventNames.neighborly_advisor, EventNames.neighborly_advisor_item,), + } + def generate_early(self) -> None: # this is specific to UT, it doesn't apply unless UT is being used self.get_options_from_slot_data(self) @@ -126,78 +147,12 @@ def create_regions(self): menu.locations.append( Sims4Location(self.player, skill_name, self.location_name_to_id.get(skill_name), menu) ) - if goal_value == goal.option_bodybuilder: - event = self.create_event_location(EventNames.bodybuilder, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.bodybuilder_item)) - elif goal_value == goal.option_painter_extraordinaire: - event = self.create_event_location(EventNames.painter_extraordinaire, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.painter_extraordinaire_item)) - elif goal_value == goal.option_bestselling_author: - event = self.create_event_location(EventNames.bestselling_author, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.bestselling_author_item)) - elif goal_value == goal.option_musical_genius: - event = self.create_event_location(EventNames.musical_genius, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.musical_genius_item)) - elif goal_value == goal.option_public_enemy: - event = self.create_event_location(EventNames.public_enemy, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.public_enemy_item)) - elif goal_value == goal.option_chief_of_mischief: - event = self.create_event_location(EventNames.chief_of_mischief, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.chief_of_mischief_item)) - elif goal_value == goal.option_master_chef: - event = self.create_event_location(EventNames.master_chef, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.master_chef_item)) - elif goal_value == goal.option_master_mixologist: - event = self.create_event_location(EventNames.master_mixologist, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.master_mixologist_item)) - elif goal_value == goal.option_renaissance_sim: - event = self.create_event_location(EventNames.renaissance_sim, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.renaissance_sim_item)) - elif goal_value == goal.option_nerd_brain: - event = self.create_event_location(EventNames.nerd_brain, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.nerd_brain_item)) - elif goal_value == goal.option_computer_whiz: - event = self.create_event_location(EventNames.computer_whiz, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.computer_whiz_item)) - elif goal_value == goal.option_serial_romantic: - event = self.create_event_location(EventNames.serial_romantic, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.serial_romantic_item)) - elif goal_value == goal.option_freelance_botanist: - event = self.create_event_location(EventNames.freelance_botanist, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.freelance_botanist_item)) - elif goal_value == goal.option_the_curator: - event = self.create_event_location(EventNames.the_curator, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.the_curator_item)) - elif goal_value == goal.option_angling_ace: - event = self.create_event_location(EventNames.angling_ace, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.angling_ace_item)) - elif goal_value == goal.option_joke_star: - event = self.create_event_location(EventNames.joke_star, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.joke_star_item)) - elif goal_value == goal.option_friend_of_the_world: - event = self.create_event_location(EventNames.friend_of_the_world, menu) - menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.friend_of_the_world_item)) - elif goal_value == goal.option_neighborly_advisor: - event = self.create_event_location(EventNames.neighborly_advisor, menu) + mapping = self.GOAL_TO_EVENT_MAPPING.get(goal_value) + if mapping: + event_name, item_name = mapping + event = self.create_event_location(event_name, menu) menu.locations.append(event) - event.place_locked_item(self.create_event(EventNames.neighborly_advisor_item)) + event.place_locked_item(self.create_event(item_name)) self.multiworld.regions.append(menu) From 05187cfdf1942a7bdf84667127672854e3f9a87c Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:10:13 -0700 Subject: [PATCH 40/71] remove extra comma --- worlds/sims4/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index c9a839260916..a2b2aefd7717 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -74,7 +74,7 @@ class Sims4World(World, UTMixin): Sims4Options.goal.option_angling_ace: (EventNames.angling_ace, EventNames.angling_ace_item), Sims4Options.goal.option_joke_star: (EventNames.joke_star, EventNames.joke_star_item), Sims4Options.goal.option_friend_of_the_world: (EventNames.friend_of_the_world, EventNames.friend_of_the_world_item), - Sims4Options.goal.option_neighborly_advisor: (EventNames.neighborly_advisor, EventNames.neighborly_advisor_item,), + Sims4Options.goal.option_neighborly_advisor: (EventNames.neighborly_advisor, EventNames.neighborly_advisor_item,) } def generate_early(self) -> None: From 79b5223ae808d2a794633ca2c5f5f83465d49be8 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:11:00 -0700 Subject: [PATCH 41/71] fix the lookup table --- worlds/sims4/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index a2b2aefd7717..068af8dc582e 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -58,8 +58,8 @@ class Sims4World(World, UTMixin): GOAL_TO_EVENT_MAPPING = { Sims4Options.goal.option_bodybuilder: (EventNames.bodybuilder, EventNames.bodybuilder_item), - Sims4Options.goal.option_painter_extraordinaire: (EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item) - Sims4Options.goal.option_bestselling_author: (EventNames.bestselling_author, EventNames.bestselling_author_item) + Sims4Options.goal.option_painter_extraordinaire: (EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item), + Sims4Options.goal.option_bestselling_author: (EventNames.bestselling_author, EventNames.bestselling_author_item), Sims4Options.goal.option_musical_genius: (EventNames.musical_genius, EventNames.musical_genius_item), Sims4Options.goal.option_public_enemy: (EventNames.public_enemy, EventNames.public_enemy_item), Sims4Options.goal.option_chief_of_mischief: (EventNames.chief_of_mischief, EventNames.chief_of_mischief_item), From 52f164d0271a475e08350213d50b279fc1aca8a9 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:14:19 -0700 Subject: [PATCH 42/71] fuck i fell in the trap again --- worlds/sims4/__init__.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 068af8dc582e..a943cb59ed0b 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -10,7 +10,7 @@ from .Locations import location_table, Sims4Location, skill_locations_table from .Items import item_table, skills_table, Sims4Item, junk_table, filler_set from .Names import EventNames -from .Options import Sims4Options +from .Options import AspirationGoal, Sims4Options from .Regions import sims4_careers, sims4_aspiration_milestones, sims4_skill_dependencies, \ sims4_regions from .Rules import set_rules @@ -57,24 +57,24 @@ class Sims4World(World, UTMixin): settings: ClassVar[Sims4Settings] GOAL_TO_EVENT_MAPPING = { - Sims4Options.goal.option_bodybuilder: (EventNames.bodybuilder, EventNames.bodybuilder_item), - Sims4Options.goal.option_painter_extraordinaire: (EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item), - Sims4Options.goal.option_bestselling_author: (EventNames.bestselling_author, EventNames.bestselling_author_item), - Sims4Options.goal.option_musical_genius: (EventNames.musical_genius, EventNames.musical_genius_item), - Sims4Options.goal.option_public_enemy: (EventNames.public_enemy, EventNames.public_enemy_item), - Sims4Options.goal.option_chief_of_mischief: (EventNames.chief_of_mischief, EventNames.chief_of_mischief_item), - Sims4Options.goal.option_master_chef: (EventNames.master_chef, EventNames.master_chef_item), - Sims4Options.goal.option_master_mixologist: (EventNames.master_mixologist, EventNames.master_mixologist_item), - Sims4Options.goal.option_renaissance_sim: (EventNames.renaissance_sim, EventNames.renaissance_sim_item), - Sims4Options.goal.option_nerd_brain: (EventNames.nerd_brain, EventNames.nerd_brain_item), - Sims4Options.goal.option_computer_whiz: (EventNames.computer_whiz, EventNames.computer_whiz_item), - Sims4Options.goal.option_serial_romantic: (EventNames.serial_romantic, EventNames.serial_romantic_item), - Sims4Options.goal.option_freelance_botanist: (EventNames.freelance_botanist, EventNames.freelance_botanist_item), - Sims4Options.goal.option_the_curator: (EventNames.the_curator, EventNames.the_curator_item), - Sims4Options.goal.option_angling_ace: (EventNames.angling_ace, EventNames.angling_ace_item), - Sims4Options.goal.option_joke_star: (EventNames.joke_star, EventNames.joke_star_item), - Sims4Options.goal.option_friend_of_the_world: (EventNames.friend_of_the_world, EventNames.friend_of_the_world_item), - Sims4Options.goal.option_neighborly_advisor: (EventNames.neighborly_advisor, EventNames.neighborly_advisor_item,) + AspirationGoal.option_bodybuilder: (EventNames.bodybuilder, EventNames.bodybuilder_item), + AspirationGoal.option_painter_extraordinaire: (EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item), + AspirationGoal.option_bestselling_author: (EventNames.bestselling_author, EventNames.bestselling_author_item), + AspirationGoal.option_musical_genius: (EventNames.musical_genius, EventNames.musical_genius_item), + AspirationGoal.option_public_enemy: (EventNames.public_enemy, EventNames.public_enemy_item), + AspirationGoal.option_chief_of_mischief: (EventNames.chief_of_mischief, EventNames.chief_of_mischief_item), + AspirationGoal.option_master_chef: (EventNames.master_chef, EventNames.master_chef_item), + AspirationGoal.option_master_mixologist: (EventNames.master_mixologist, EventNames.master_mixologist_item), + AspirationGoal.option_renaissance_sim: (EventNames.renaissance_sim, EventNames.renaissance_sim_item), + AspirationGoal.option_nerd_brain: (EventNames.nerd_brain, EventNames.nerd_brain_item), + AspirationGoal.option_computer_whiz: (EventNames.computer_whiz, EventNames.computer_whiz_item), + AspirationGoal.option_serial_romantic: (EventNames.serial_romantic, EventNames.serial_romantic_item), + AspirationGoal.option_freelance_botanist: (EventNames.freelance_botanist, EventNames.freelance_botanist_item), + AspirationGoal.option_the_curator: (EventNames.the_curator, EventNames.the_curator_item), + AspirationGoal.option_angling_ace: (EventNames.angling_ace, EventNames.angling_ace_item), + AspirationGoal.option_joke_star: (EventNames.joke_star, EventNames.joke_star_item), + AspirationGoal.option_friend_of_the_world: (EventNames.friend_of_the_world, EventNames.friend_of_the_world_item), + AspirationGoal.option_neighborly_advisor: (EventNames.neighborly_advisor, EventNames.neighborly_advisor_item,) } def generate_early(self) -> None: From b3741f386bc258cee821b49c28996b71c9a0d147 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:15:11 -0700 Subject: [PATCH 43/71] remove old code again --- worlds/sims4/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index a943cb59ed0b..699d1d86fe0f 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -160,7 +160,6 @@ def set_rules(self) -> None: set_rules(self.multiworld, self.player, self.options) def fill_slot_data(self) -> Mapping[str, Any]: - # slot_data = self.options.as_dict("goal", "career", "expansion_packs", "game_packs", "stuff_packs", "cas_kits", "build_kits") slot_data = { "goal": self.options.goal.current_key, "career": self.options.career.value, From 5986e9390a422c694b4b50b5ccce3a97f3521f5a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:16:32 -0700 Subject: [PATCH 44/71] remove unused imports --- worlds/sims4/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 699d1d86fe0f..e66d6241cd3a 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -8,11 +8,10 @@ # TS4 specific imports from .Locations import location_table, Sims4Location, skill_locations_table -from .Items import item_table, skills_table, Sims4Item, junk_table, filler_set +from .Items import item_table, Sims4Item, junk_table, filler_set from .Names import EventNames from .Options import AspirationGoal, Sims4Options -from .Regions import sims4_careers, sims4_aspiration_milestones, sims4_skill_dependencies, \ - sims4_regions +from .Regions import sims4_careers, sims4_aspiration_milestones from .Rules import set_rules from .Groups import location_name_groups, item_name_groups from .UT import UTMixin From 233e2003fc6848396ac4db96f19f62e5806e12c3 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:18:20 -0700 Subject: [PATCH 45/71] whitespace stuff --- worlds/sims4/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index e66d6241cd3a..f155cc489bbd 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -19,6 +19,7 @@ from .Web import Sims4Web from .Version import VERSION, Sims4Version + def run_client(*args: str) -> None: from .Client import main launch(main, name="The Sims 4 Client", args=args) @@ -28,6 +29,7 @@ def run_client(*args: str) -> None: icon_paths["plumbob"] = f"ap:{__name__}/icons/plumbob.png" + class Sims4World(World, UTMixin): """ The Sims 4 is the fourth installment in The Sims franchise. Like the previous games in the series, @@ -80,7 +82,6 @@ def generate_early(self) -> None: # this is specific to UT, it doesn't apply unless UT is being used self.get_options_from_slot_data(self) - def create_item(self, name: str) -> Item: item_id: int = self.item_name_to_id[name] From c1e2c60b70bfbce45bc54913cf222b57696d136c Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:40:42 -0700 Subject: [PATCH 46/71] type the lookup table & remove trailing comma --- worlds/sims4/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index f155cc489bbd..277cf4b27be7 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -57,7 +57,7 @@ class Sims4World(World, UTMixin): settings: ClassVar[Sims4Settings] - GOAL_TO_EVENT_MAPPING = { + GOAL_TO_EVENT_MAPPING: ClassVar = { AspirationGoal.option_bodybuilder: (EventNames.bodybuilder, EventNames.bodybuilder_item), AspirationGoal.option_painter_extraordinaire: (EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item), AspirationGoal.option_bestselling_author: (EventNames.bestselling_author, EventNames.bestselling_author_item), @@ -75,7 +75,7 @@ class Sims4World(World, UTMixin): AspirationGoal.option_angling_ace: (EventNames.angling_ace, EventNames.angling_ace_item), AspirationGoal.option_joke_star: (EventNames.joke_star, EventNames.joke_star_item), AspirationGoal.option_friend_of_the_world: (EventNames.friend_of_the_world, EventNames.friend_of_the_world_item), - AspirationGoal.option_neighborly_advisor: (EventNames.neighborly_advisor, EventNames.neighborly_advisor_item,) + AspirationGoal.option_neighborly_advisor: (EventNames.neighborly_advisor, EventNames.neighborly_advisor_item) } def generate_early(self) -> None: From a557aace7f9f64c38afbb59cf74c05aa7d9260b4 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:48:04 -0700 Subject: [PATCH 47/71] typing --- worlds/sims4/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 277cf4b27be7..7db25e488d37 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -57,7 +57,7 @@ class Sims4World(World, UTMixin): settings: ClassVar[Sims4Settings] - GOAL_TO_EVENT_MAPPING: ClassVar = { + GOAL_TO_EVENT_MAPPING: ClassVar[dict[int, tuple[str, str]]] = { AspirationGoal.option_bodybuilder: (EventNames.bodybuilder, EventNames.bodybuilder_item), AspirationGoal.option_painter_extraordinaire: (EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item), AspirationGoal.option_bestselling_author: (EventNames.bestselling_author, EventNames.bestselling_author_item), @@ -82,17 +82,17 @@ def generate_early(self) -> None: # this is specific to UT, it doesn't apply unless UT is being used self.get_options_from_slot_data(self) - def create_item(self, name: str) -> Item: + def create_item(self, name: str) -> Sims4Item: item_id: int = self.item_name_to_id[name] return Sims4Item(name, item_table[item_id]["classification"], item_id, player=self.player) - def create_event(self, event: str): + def create_event(self, event: str) -> Sims4Item: return Sims4Item(event, ItemClassification.progression, None, self.player) - def create_event_location(self, event: str, region: Region): + def create_event_location(self, event: str, region: Region) -> Sims4Location: return Sims4Location(self.player, event, None, region) def create_items(self) -> None: @@ -114,7 +114,7 @@ def create_items(self) -> None: self.multiworld.itempool += pool - def create_region(self, name: str, locations=None, exits=None): + def create_region(self, name: str, locations=None, exits=None) -> Region: ret = Region(name, self.player, self.multiworld) if locations: for location in locations: @@ -126,7 +126,7 @@ def create_region(self, name: str, locations=None, exits=None): ret.exits.append(Entrance(self.player, region_exit, ret)) return ret - def create_regions(self): + def create_regions(self) -> None: menu = self.create_region("Menu", locations=None, exits=None) chosen_careers = sorted(self.options.career.value) goal = self.options.goal From c462db27ab1886b6a002b931e6231207739afdd3 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 16:54:27 -0700 Subject: [PATCH 48/71] add eije's test thingy --- .github/workflows/test.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000000..4bf24a207980 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,18 @@ +name: Test apworld +on: + push: + pull_request: + +jobs: + tests: + runs-on: ubuntu-latest + steps: + - name: Get latest AP Version + id: get_latest_ap_version + run: | + echo "AP_VERSION=`wget https://github.com/ArchipelagoMW/Archipelago/releases/latest 2>&1 | grep Location: | awk '{print $2}' | rev | cut -d "/" -f 1 | rev`" >> "$GITHUB_ENV" + - uses: Eijebong/ap-actions/ap-tests@main + with: + apworld-path: worlds/sims4 + ap-version: ${{ env.AP_VERSION }} + python-version: '3.12' \ No newline at end of file From ce58185b28b56f3c7f645a7632acfd54ded1ada3 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 6 Jan 2026 17:35:39 -0700 Subject: [PATCH 49/71] unused import (again) --- worlds/sims4/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 7db25e488d37..5491a79888b4 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -2,7 +2,7 @@ from typing import Mapping, Any, ClassVar # ap imports -from BaseClasses import Item, ItemClassification, Region, Entrance +from BaseClasses import ItemClassification, Region, Entrance from worlds.AutoWorld import World from ..LauncherComponents import Component, components, Type, icon_paths, launch From 7012b743630bf1f045dbedca591c79b8dbad0f0a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 00:05:50 -0700 Subject: [PATCH 50/71] fix some small things --- worlds/sims4/__init__.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 5491a79888b4..214c75947ba2 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -96,7 +96,11 @@ def create_event_location(self, event: str, region: Region) -> Sims4Location: return Sims4Location(self.player, event, None, region) def create_items(self) -> None: - used_dlc = set(self.options.expansion_packs.value | self.options.game_packs.value | self.options.stuff_packs.value) + used_dlc = set( + self.options.expansion_packs.value | + self.options.game_packs.value | + self.options.stuff_packs.value + ) pool = [] unfilled_locations = len(self.multiworld.get_unfilled_locations(self.player)) @@ -114,7 +118,7 @@ def create_items(self) -> None: self.multiworld.itempool += pool - def create_region(self, name: str, locations=None, exits=None) -> Region: + def create_region(self, name: str, locations: list[str] | None = None, exits: list[str] | None = None) -> Region: ret = Region(name, self.player, self.multiworld) if locations: for location in locations: @@ -140,7 +144,11 @@ def create_regions(self) -> None: menu.locations.append( Sims4Location(self.player, aspiration, self.location_name_to_id.get(aspiration), menu) ) - used_dlc = set(self.options.expansion_packs.value | self.options.game_packs.value | self.options.stuff_packs.value) + used_dlc = set( + self.options.expansion_packs.value | + self.options.game_packs.value | + self.options.stuff_packs.value + ) for skill in skill_locations_table.values(): skill_name = skill["name"] if skill['expansion'] == 'base' or skill['expansion'] in used_dlc: From 61ae538440ddfbfbdb663d0585bb42ebc7ae72c2 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 00:07:20 -0700 Subject: [PATCH 51/71] another typing thing --- worlds/sims4/Items.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/sims4/Items.py b/worlds/sims4/Items.py index e9670b592fc1..f643ff673619 100644 --- a/worlds/sims4/Items.py +++ b/worlds/sims4/Items.py @@ -97,7 +97,7 @@ def add_skill(skill_name: str, expansion: str, max_level: int) -> int: add_skill(SkillNames.ebn_apothecary_skill, ExpansionNames.enchanted_by_nature, 10) add_skill(SkillNames.ebn_natural_living_skill, ExpansionNames.enchanted_by_nature, 10) -useful_table = { +useful_table: dict[int, ItemDict] = { 0x733400FF: {'classification': ItemClassification.useful, 'count': 4, 'name': UsefulNames.skill_gain_boost, @@ -106,7 +106,7 @@ def add_skill(skill_name: str, expansion: str, max_level: int) -> int: } -junk_table = { +junk_table: dict[int, ItemDict] = { 0x73340FFF: {'classification': ItemClassification.filler, 'count': 0, 'name': JunkNames.twothousand_simoleons, From 41579963acc83068abf304751e306692ad40f7a9 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 00:54:20 -0700 Subject: [PATCH 52/71] fix pep8 --- worlds/sims4/Items.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/sims4/Items.py b/worlds/sims4/Items.py index f643ff673619..f11dc08d814f 100644 --- a/worlds/sims4/Items.py +++ b/worlds/sims4/Items.py @@ -5,6 +5,7 @@ from .Names import SkillNames, JunkNames, UsefulNames from .Names.DLC import ExpansionNames, GamePackNames, StuffNames + class ItemDict(TypedDict): classification: ItemClassification count: int @@ -24,6 +25,7 @@ class Sims4Item(Item): skills_table: dict[int, ItemDict] = {} + def add_skill(skill_name: str, expansion: str, max_level: int) -> int: if skills_table: skill_id = max(skills_table.keys()) + 1 @@ -39,6 +41,7 @@ def add_skill(skill_name: str, expansion: str, max_level: int) -> int: } return skill_id + add_skill(SkillNames.base_skill_comedy, ExpansionNames.base, 10) add_skill(SkillNames.base_skill_guitar, ExpansionNames.base, 10) add_skill(SkillNames.base_skill_logic, ExpansionNames.base, 10) From 8c88da191669c23b7ae026e8f2b1281a88d5ddf6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 01:01:37 -0700 Subject: [PATCH 53/71] some small tweaks (other than that should be good) --- worlds/sims4/Items.py | 4 +++- worlds/sims4/Locations.py | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/worlds/sims4/Items.py b/worlds/sims4/Items.py index f11dc08d814f..e97fd44b6fd4 100644 --- a/worlds/sims4/Items.py +++ b/worlds/sims4/Items.py @@ -27,13 +27,15 @@ class Sims4Item(Item): def add_skill(skill_name: str, expansion: str, max_level: int) -> int: + if max_level < 2: + raise ValueError(f"max_level must be at least 2, got {max_level}") if skills_table: skill_id = max(skills_table.keys()) + 1 else: skill_id = 0x7334001 skills_table[skill_id] = { - "name": f"{skill_name}", + "name": skill_name, "classification": ItemClassification.progression, "count": max_level - 2, "tech_type": "Skill", diff --git a/worlds/sims4/Locations.py b/worlds/sims4/Locations.py index 66097397a37e..396be2c409c4 100644 --- a/worlds/sims4/Locations.py +++ b/worlds/sims4/Locations.py @@ -83,7 +83,7 @@ def add_skill_location(skill_name: str, expansion: str, max_level: int) -> int: add_skill_location(SkillNames.du_robotics_skill, ExpansionNames.discover_university, 10) add_skill_location(SkillNames.el_fabrication_skill, ExpansionNames.eco_lifestyle, 10) add_skill_location(SkillNames.el_juicefizzing_skill, ExpansionNames.eco_lifestyle, 5) -add_skill_location(SkillNames.nk_knitting_skill, StuffNames.nifty_knitting, 10) +add_skill_location(SkillNames.nk_knitting_skill, StuffNames.nifty_knitting, 10) add_skill_location(SkillNames.sy_rock_climbing_skill, ExpansionNames.snowy_escape, 10) add_skill_location(SkillNames.sy_skiing_skill, ExpansionNames.snowy_escape, 10) add_skill_location(SkillNames.sy_snowboarding_skill, ExpansionNames.snowy_escape, 10) @@ -103,7 +103,7 @@ def add_skill_location(skill_name: str, expansion: str, max_level: int) -> int: del add_skill_location -careers_locations_table = { +careers_locations_table: dict[int, Sims4LocationDict] = { 0x73342001: {"name": f"{CareerNames.base_career_athlete_2}", "category": "Athlete", @@ -568,7 +568,7 @@ def add_skill_location(skill_name: str, expansion: str, max_level: int) -> int: } -ptj_locations_table = { +ptj_locations_table: dict[int, Sims4LocationDict] = { 0x733420A2: {"name": f"{CareerNames.base_ptj_babysitter_2}", "category": "Babysitter", @@ -606,7 +606,7 @@ def add_skill_location(skill_name: str, expansion: str, max_level: int) -> int: "expansion": "base"}, } -aspiration_locations_table = { +aspiration_locations_table: dict[int, Sims4LocationDict] = { 0x73343000: {"name": f"{AspirationNames.base_aspiration_basic_trainer}", "category": "Aspirations", "expansion": "base"}, @@ -882,7 +882,7 @@ def add_skill_location(skill_name: str, expansion: str, max_level: int) -> int: "expansion": "base"}, } -location_table = { +location_table: dict[int, Sims4LocationDict] = { **skill_locations_table, **careers_locations_table, **aspiration_locations_table, From b57fc7bf250681d8fe15b27dea986c7e51604758 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 01:44:29 -0700 Subject: [PATCH 54/71] oops extra space :D --- worlds/sims4/Items.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/Items.py b/worlds/sims4/Items.py index e97fd44b6fd4..9f30e68074aa 100644 --- a/worlds/sims4/Items.py +++ b/worlds/sims4/Items.py @@ -85,7 +85,7 @@ def add_skill(skill_name: str, expansion: str, max_level: int) -> int: add_skill(SkillNames.du_robotics_skill, ExpansionNames.discover_university, 10) add_skill(SkillNames.el_fabrication_skill, ExpansionNames.eco_lifestyle, 10) add_skill(SkillNames.el_juicefizzing_skill, ExpansionNames.eco_lifestyle, 5) -add_skill(SkillNames.nk_knitting_skill, StuffNames.nifty_knitting, 10) +add_skill(SkillNames.nk_knitting_skill, StuffNames.nifty_knitting, 10) add_skill(SkillNames.sy_rock_climbing_skill, ExpansionNames.snowy_escape, 10) add_skill(SkillNames.sy_skiing_skill, ExpansionNames.snowy_escape, 10) add_skill(SkillNames.sy_snowboarding_skill, ExpansionNames.snowy_escape, 10) From 86b183231038c52cc1c4a52a583814883af20924 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 01:46:41 -0700 Subject: [PATCH 55/71] fix the extra space and make a new error type --- worlds/sims4/Items.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/worlds/sims4/Items.py b/worlds/sims4/Items.py index 9f30e68074aa..ad1217531441 100644 --- a/worlds/sims4/Items.py +++ b/worlds/sims4/Items.py @@ -26,9 +26,13 @@ class Sims4Item(Item): skills_table: dict[int, ItemDict] = {} +class SkillConfigError(ValueError): + """Raised when skill configuration is invalid.""" + pass + def add_skill(skill_name: str, expansion: str, max_level: int) -> int: if max_level < 2: - raise ValueError(f"max_level must be at least 2, got {max_level}") + raise SkillConfigError(f"max_level must be at least 2, got {max_level}") if skills_table: skill_id = max(skills_table.keys()) + 1 else: From 534f139e476ec43b16590a4dd86646da2dbd816c Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 02:01:25 -0700 Subject: [PATCH 56/71] fixywixy --- worlds/sims4/Items.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/Items.py b/worlds/sims4/Items.py index ad1217531441..3b6761e986e7 100644 --- a/worlds/sims4/Items.py +++ b/worlds/sims4/Items.py @@ -28,7 +28,7 @@ class Sims4Item(Item): class SkillConfigError(ValueError): """Raised when skill configuration is invalid.""" - pass + def add_skill(skill_name: str, expansion: str, max_level: int) -> int: if max_level < 2: From 5215c27c1c5ed0a463a7d8ad7a8c063c6c02410f Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 08:13:12 -0700 Subject: [PATCH 57/71] fix some formatting --- worlds/sims4/Locations.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/worlds/sims4/Locations.py b/worlds/sims4/Locations.py index 396be2c409c4..3e3191ceac23 100644 --- a/worlds/sims4/Locations.py +++ b/worlds/sims4/Locations.py @@ -27,6 +27,7 @@ class Sims4LocationData(NamedTuple): skill_locations_table: dict[int, Sims4LocationDict] = {} + def add_skill_location(skill_name: str, expansion: str, max_level: int) -> int: if skill_locations_table: start_id = max(skill_locations_table.keys()) @@ -42,6 +43,7 @@ def add_skill_location(skill_name: str, expansion: str, max_level: int) -> int: } return skill_id + add_skill_location(SkillNames.base_skill_comedy, ExpansionNames.base, 10) add_skill_location(SkillNames.base_skill_guitar, ExpansionNames.base, 10) add_skill_location(SkillNames.base_skill_logic, ExpansionNames.base, 10) @@ -97,8 +99,8 @@ def add_skill_location(skill_name: str, expansion: str, max_level: int) -> int: add_skill_location(SkillNames.lnd_thanatology_skill, ExpansionNames.life_and_death, 5) add_skill_location(SkillNames.bnh_pottery_skill, ExpansionNames.business_and_hobbies, 10) add_skill_location(SkillNames.bnh_tattooing_skill, ExpansionNames.business_and_hobbies, 10) -add_skill_location(SkillNames.ebn_apothecary_skill, ExpansionNames.enchanted_by_nature , 10) -add_skill_location(SkillNames.ebn_natural_living_skill, ExpansionNames.enchanted_by_nature , 10) +add_skill_location(SkillNames.ebn_apothecary_skill, ExpansionNames.enchanted_by_nature, 10) +add_skill_location(SkillNames.ebn_natural_living_skill, ExpansionNames.enchanted_by_nature, 10) del add_skill_location From a42364042ce4f4bbe055c79d6da32a1f5e79b475 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 08:14:36 -0700 Subject: [PATCH 58/71] fix a pep8 --- worlds/sims4/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 214c75947ba2..d0f16b06fbed 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -59,7 +59,9 @@ class Sims4World(World, UTMixin): GOAL_TO_EVENT_MAPPING: ClassVar[dict[int, tuple[str, str]]] = { AspirationGoal.option_bodybuilder: (EventNames.bodybuilder, EventNames.bodybuilder_item), - AspirationGoal.option_painter_extraordinaire: (EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item), + AspirationGoal.option_painter_extraordinaire: ( + EventNames.painter_extraordinaire, EventNames.painter_extraordinaire_item + ), AspirationGoal.option_bestselling_author: (EventNames.bestselling_author, EventNames.bestselling_author_item), AspirationGoal.option_musical_genius: (EventNames.musical_genius, EventNames.musical_genius_item), AspirationGoal.option_public_enemy: (EventNames.public_enemy, EventNames.public_enemy_item), @@ -75,7 +77,9 @@ class Sims4World(World, UTMixin): AspirationGoal.option_angling_ace: (EventNames.angling_ace, EventNames.angling_ace_item), AspirationGoal.option_joke_star: (EventNames.joke_star, EventNames.joke_star_item), AspirationGoal.option_friend_of_the_world: (EventNames.friend_of_the_world, EventNames.friend_of_the_world_item), - AspirationGoal.option_neighborly_advisor: (EventNames.neighborly_advisor, EventNames.neighborly_advisor_item) + AspirationGoal.option_neighborly_advisor: ( + EventNames.neighborly_advisor, EventNames.neighborly_advisor_item + ) } def generate_early(self) -> None: From 1a956837cc322237805d5024019a55ca6f4f655a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 10:26:32 -0700 Subject: [PATCH 59/71] i think this is actually better --- worlds/sims4/Locations.py | 4 ---- worlds/sims4/__init__.py | 9 ++++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/worlds/sims4/Locations.py b/worlds/sims4/Locations.py index 3e3191ceac23..41711504c613 100644 --- a/worlds/sims4/Locations.py +++ b/worlds/sims4/Locations.py @@ -9,10 +9,6 @@ class Sims4Location(Location): game: str = "The Sims 4" - def __init__(self, player: int, name: str, address: Optional[int], parent): - super().__init__(player, name, address, parent) - self.event = not address - class Sims4LocationDict(TypedDict, total=False): name: str diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index d0f16b06fbed..48404af75392 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -1,5 +1,5 @@ # standard lib imports -from typing import Mapping, Any, ClassVar +from typing import Mapping, Any, ClassVar, Optional # ap imports from BaseClasses import ItemClassification, Region, Entrance @@ -96,8 +96,11 @@ def create_item(self, name: str) -> Sims4Item: def create_event(self, event: str) -> Sims4Item: return Sims4Item(event, ItemClassification.progression, None, self.player) - def create_event_location(self, event: str, region: Region) -> Sims4Location: - return Sims4Location(self.player, event, None, region) + def create_event_location(self, event: str, region: Optional[Region]) -> Sims4Location: + if region is not None: + return Sims4Location(self.player, event, None, region) + else: + return Sims4Location(self.player, event, None) def create_items(self) -> None: used_dlc = set( From fabfd7486333f017ad0b8d86c80cc3e416799211 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 10:33:46 -0700 Subject: [PATCH 60/71] stop shadowing the thing --- worlds/sims4/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 48404af75392..cfb29c99a5a2 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -128,9 +128,9 @@ def create_items(self) -> None: def create_region(self, name: str, locations: list[str] | None = None, exits: list[str] | None = None) -> Region: ret = Region(name, self.player, self.multiworld) if locations: - for location in locations: - loc_id = self.location_name_to_id.get(location, None) - location = Sims4Location(self.player, location, loc_id, ret) + for location_name in locations: + loc_id = self.location_name_to_id.get(location_name, None) + location = Sims4Location(self.player, location_name, loc_id, ret) ret.locations.append(location) if exits: for region_exit in exits: From ef0feb4fbfa880f7eb899915a97f9281177dfe36 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 10:36:39 -0700 Subject: [PATCH 61/71] actually make the thing optional and use it in the event thing --- worlds/sims4/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index cfb29c99a5a2..0097386b91e5 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -96,7 +96,7 @@ def create_item(self, name: str) -> Sims4Item: def create_event(self, event: str) -> Sims4Item: return Sims4Item(event, ItemClassification.progression, None, self.player) - def create_event_location(self, event: str, region: Optional[Region]) -> Sims4Location: + def create_event_location(self, event: str, region: Optional[Region] = None) -> Sims4Location: if region is not None: return Sims4Location(self.player, event, None, region) else: @@ -165,7 +165,7 @@ def create_regions(self) -> None: mapping = self.GOAL_TO_EVENT_MAPPING.get(goal_value) if mapping: event_name, item_name = mapping - event = self.create_event_location(event_name, menu) + event = self.create_event_location(event_name) menu.locations.append(event) event.place_locked_item(self.create_event(item_name)) From db70ed806e3613558d1b06bff3c34f951f092cb3 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 10:46:43 -0700 Subject: [PATCH 62/71] add create location helper --- worlds/sims4/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 0097386b91e5..25a3ba2f2cd5 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -91,7 +91,12 @@ def create_item(self, name: str) -> Sims4Item: return Sims4Item(name, item_table[item_id]["classification"], - item_id, player=self.player) + item_id, self.player) + + def create_location(self, name: str) -> Sims4Location: + location_id: int = self.location_name_to_id[name] + + return Sims4Location(self.player, name, location_id) def create_event(self, event: str) -> Sims4Item: return Sims4Item(event, ItemClassification.progression, None, self.player) From 4c243035a7c10636111cb5a5be11b42626c717f4 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 10:51:01 -0700 Subject: [PATCH 63/71] refactor to use the new location helper --- worlds/sims4/__init__.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 25a3ba2f2cd5..5a761491569e 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -134,8 +134,7 @@ def create_region(self, name: str, locations: list[str] | None = None, exits: li ret = Region(name, self.player, self.multiworld) if locations: for location_name in locations: - loc_id = self.location_name_to_id.get(location_name, None) - location = Sims4Location(self.player, location_name, loc_id, ret) + location = self.create_location(location_name) ret.locations.append(location) if exits: for region_exit in exits: @@ -150,12 +149,9 @@ def create_regions(self) -> None: aspiration_key = goal.current_key for career_key in chosen_careers: for career in sims4_careers[career_key.lower().replace(" ", "_")]: - menu.locations.append( - Sims4Location(self.player, career, self.location_name_to_id.get(career), menu)) - for aspiration in sims4_aspiration_milestones[aspiration_key]: - menu.locations.append( - Sims4Location(self.player, aspiration, self.location_name_to_id.get(aspiration), menu) - ) + menu.locations.append(self.create_location(career)) + for aspiration in sims4_aspiration_milestones[aspiration_key]: # (change this later, we'll need it to do the multi aspiration thing that's in another branch) + menu.locations.append(self.create_location(aspiration)) used_dlc = set( self.options.expansion_packs.value | self.options.game_packs.value | @@ -164,9 +160,7 @@ def create_regions(self) -> None: for skill in skill_locations_table.values(): skill_name = skill["name"] if skill['expansion'] == 'base' or skill['expansion'] in used_dlc: - menu.locations.append( - Sims4Location(self.player, skill_name, self.location_name_to_id.get(skill_name), menu) - ) + menu.locations.append(self.create_location(skill_name)) mapping = self.GOAL_TO_EVENT_MAPPING.get(goal_value) if mapping: event_name, item_name = mapping From ad5b093e561fe7a15707518aae50fbf0b85c485d Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 10:54:02 -0700 Subject: [PATCH 64/71] use the right Mapping --- worlds/sims4/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 5a761491569e..2cacfe52f613 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -1,5 +1,6 @@ # standard lib imports -from typing import Mapping, Any, ClassVar, Optional +from typing import Any, ClassVar, Optional +from collections.abc import Mapping # ap imports from BaseClasses import ItemClassification, Region, Entrance From 9f3f7a563ee449705f1ac48f3f34719e7c2281ee Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 10:54:50 -0700 Subject: [PATCH 65/71] line length --- worlds/sims4/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index 2cacfe52f613..c6969a5dae38 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -77,7 +77,9 @@ class Sims4World(World, UTMixin): AspirationGoal.option_the_curator: (EventNames.the_curator, EventNames.the_curator_item), AspirationGoal.option_angling_ace: (EventNames.angling_ace, EventNames.angling_ace_item), AspirationGoal.option_joke_star: (EventNames.joke_star, EventNames.joke_star_item), - AspirationGoal.option_friend_of_the_world: (EventNames.friend_of_the_world, EventNames.friend_of_the_world_item), + AspirationGoal.option_friend_of_the_world: ( + EventNames.friend_of_the_world, EventNames.friend_of_the_world_item + ), AspirationGoal.option_neighborly_advisor: ( EventNames.neighborly_advisor, EventNames.neighborly_advisor_item ) From e58e6de874b339013aeef2c7a209054359be9070 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 10:59:17 -0700 Subject: [PATCH 66/71] okay that went horribly wrong --- worlds/sims4/__init__.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index c6969a5dae38..aabceb6eea48 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -96,19 +96,16 @@ def create_item(self, name: str) -> Sims4Item: item_table[item_id]["classification"], item_id, self.player) - def create_location(self, name: str) -> Sims4Location: + def create_location(self, name: str, parent: Region) -> Sims4Location: location_id: int = self.location_name_to_id[name] - return Sims4Location(self.player, name, location_id) + return Sims4Location(self.player, name, location_id, parent) def create_event(self, event: str) -> Sims4Item: return Sims4Item(event, ItemClassification.progression, None, self.player) - def create_event_location(self, event: str, region: Optional[Region] = None) -> Sims4Location: - if region is not None: - return Sims4Location(self.player, event, None, region) - else: - return Sims4Location(self.player, event, None) + def create_event_location(self, event: str, region: Region) -> Sims4Location: + return Sims4Location(self.player, event, None, region) def create_items(self) -> None: used_dlc = set( @@ -137,7 +134,7 @@ def create_region(self, name: str, locations: list[str] | None = None, exits: li ret = Region(name, self.player, self.multiworld) if locations: for location_name in locations: - location = self.create_location(location_name) + location = self.create_location(location_name, ret) ret.locations.append(location) if exits: for region_exit in exits: @@ -152,9 +149,9 @@ def create_regions(self) -> None: aspiration_key = goal.current_key for career_key in chosen_careers: for career in sims4_careers[career_key.lower().replace(" ", "_")]: - menu.locations.append(self.create_location(career)) + menu.locations.append(self.create_location(career, menu)) for aspiration in sims4_aspiration_milestones[aspiration_key]: # (change this later, we'll need it to do the multi aspiration thing that's in another branch) - menu.locations.append(self.create_location(aspiration)) + menu.locations.append(self.create_location(aspiration, menu)) used_dlc = set( self.options.expansion_packs.value | self.options.game_packs.value | @@ -163,11 +160,11 @@ def create_regions(self) -> None: for skill in skill_locations_table.values(): skill_name = skill["name"] if skill['expansion'] == 'base' or skill['expansion'] in used_dlc: - menu.locations.append(self.create_location(skill_name)) + menu.locations.append(self.create_location(skill_name, menu)) mapping = self.GOAL_TO_EVENT_MAPPING.get(goal_value) if mapping: event_name, item_name = mapping - event = self.create_event_location(event_name) + event = self.create_event_location(event_name, menu) menu.locations.append(event) event.place_locked_item(self.create_event(item_name)) From 60d9bb7e54a12e1fee8ac309c78585da1b84c0fe Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 11:01:03 -0700 Subject: [PATCH 67/71] remove the comment (i misinterpreted) --- worlds/sims4/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index aabceb6eea48..c799d7450b3b 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -150,7 +150,7 @@ def create_regions(self) -> None: for career_key in chosen_careers: for career in sims4_careers[career_key.lower().replace(" ", "_")]: menu.locations.append(self.create_location(career, menu)) - for aspiration in sims4_aspiration_milestones[aspiration_key]: # (change this later, we'll need it to do the multi aspiration thing that's in another branch) + for aspiration in sims4_aspiration_milestones[aspiration_key]: menu.locations.append(self.create_location(aspiration, menu)) used_dlc = set( self.options.expansion_packs.value | From 9668878b852da8d678fc907564387a05e634440e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 11:03:50 -0700 Subject: [PATCH 68/71] update the version (i can't believe i forgot) --- worlds/sims4/Version.py | 2 +- worlds/sims4/archipelago.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/sims4/Version.py b/worlds/sims4/Version.py index 688056448192..f69a085b2882 100644 --- a/worlds/sims4/Version.py +++ b/worlds/sims4/Version.py @@ -1,4 +1,4 @@ -VERSION: tuple[int, int, int] | tuple[int, int, int, str] = (2, 0, 0, "rc2") +VERSION: tuple[int, int, int] | tuple[int, int, int, str] = (2, 0, 0, "rc3") class Sims4Version: diff --git a/worlds/sims4/archipelago.json b/worlds/sims4/archipelago.json index b89d0e7a8db4..464cdbf7753e 100644 --- a/worlds/sims4/archipelago.json +++ b/worlds/sims4/archipelago.json @@ -1,6 +1,6 @@ { "game": "The Sims 4", "world_version": "2.0.0", - "world_version_full": "2.0.0-beta2", + "world_version_full": "2.0.0-beta3", "contributors": ["mrsummer360", "itsmisscactus", "silasary"] } From 0da7c4e2802f1ed035fa8a1baca2c571eec87df5 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 14:57:52 -0700 Subject: [PATCH 69/71] remove unused import --- worlds/sims4/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/sims4/__init__.py b/worlds/sims4/__init__.py index c799d7450b3b..e578135e1a0a 100644 --- a/worlds/sims4/__init__.py +++ b/worlds/sims4/__init__.py @@ -1,5 +1,5 @@ # standard lib imports -from typing import Any, ClassVar, Optional +from typing import Any, ClassVar from collections.abc import Mapping # ap imports From 8f91f0971dc6dfcdfb3a2869d0322cd708d53df6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 7 Jan 2026 15:05:55 -0700 Subject: [PATCH 70/71] fix the length of the line here --- worlds/sims4/Version.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worlds/sims4/Version.py b/worlds/sims4/Version.py index f69a085b2882..1a738e528a07 100644 --- a/worlds/sims4/Version.py +++ b/worlds/sims4/Version.py @@ -26,5 +26,8 @@ def is_rc(version: tuple[int, int, int] | tuple[int, int, int, str]) -> bool: return len(version) == 4 @staticmethod - def does_major_version_mismatch(client_version: tuple[int, int, int] | tuple[int, int, int, str], server_version: tuple[int, int, int] | tuple[int, int, int, str]) -> bool: + def does_major_version_mismatch( + client_version: tuple[int, int, int] | tuple[int, int, int, str], + server_version: tuple[int, int, int] | tuple[int, int, int, str] + ) -> bool: return client_version[0] != server_version[0] From e1ec54a52d6b4cee2b9765364dcd17881bbea8b2 Mon Sep 17 00:00:00 2001 From: Benny D <78334662+benny-dreamly@users.noreply.github.com> Date: Wed, 7 Jan 2026 21:18:33 -0700 Subject: [PATCH 71/71] Update .github/workflows/test.yml Co-authored-by: Katelyn Gigante --- .github/workflows/test.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4bf24a207980..3f991ef96aa1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,12 +7,8 @@ jobs: tests: runs-on: ubuntu-latest steps: - - name: Get latest AP Version - id: get_latest_ap_version - run: | - echo "AP_VERSION=`wget https://github.com/ArchipelagoMW/Archipelago/releases/latest 2>&1 | grep Location: | awk '{print $2}' | rev | cut -d "/" -f 1 | rev`" >> "$GITHUB_ENV" - uses: Eijebong/ap-actions/ap-tests@main with: apworld-path: worlds/sims4 - ap-version: ${{ env.AP_VERSION }} + ap-version: latest python-version: '3.12' \ No newline at end of file