diff --git a/worlds/sms/__init__.py b/worlds/sms/__init__.py index ed38d012c82f..abfdd70b950a 100644 --- a/worlds/sms/__init__.py +++ b/worlds/sms/__init__.py @@ -78,8 +78,6 @@ class SmsWorld(World): game = "Super Mario Sunshine" web = SmsWebWorld() - data_version = 1 - options_dataclass = SmsOptions options: SmsOptions @@ -292,7 +290,7 @@ def fill_slot_data(self) -> Dict[str, Any]: slot_data[child_option] = getattr(self.options, child_option).value slot_data["death_link"] = self.options.death_link.value - slot_data["ticket_chosen"] = self.ticket_chosen, + slot_data["ticket_chosen"] = self.ticket_chosen slot_data["seed"] = str(self.multiworld.seed_name) return slot_data diff --git a/worlds/sms/regions.py b/worlds/sms/regions.py index 2db1a05e16a1..10fefb07c73a 100644 --- a/worlds/sms/regions.py +++ b/worlds/sms/regions.py @@ -238,7 +238,6 @@ def create_region(region: SmsRegion, world: "SmsWorld"): f"{curr_region.name} - {shine.name}", region, get_correct_requirements(shine, world.options.difficulty), - True, ) if region.trade: shine_loc.trades_req = True @@ -251,7 +250,6 @@ def create_region(region: SmsRegion, world: "SmsWorld"): f"{curr_region.name} - {blue_coin.name}", region, get_correct_requirements(blue_coin, world.options.difficulty), - True, ) if world.options.blue_coin_sanity.value != 1: curr_region.add_event( diff --git a/worlds/sms/sms_regions/sms_region_helper.py b/worlds/sms/sms_regions/sms_region_helper.py index 2b9ec7f32752..d3f8b8c4e67d 100644 --- a/worlds/sms/sms_regions/sms_region_helper.py +++ b/worlds/sms/sms_regions/sms_region_helper.py @@ -14,7 +14,6 @@ class SmsLocation(Location): sms_region: "SmsRegion" loc_reqs: list["Requirements"] corona: bool - requirements_logic_any: bool def __init__( self, @@ -22,13 +21,11 @@ def __init__( name: str, parent_region: "SmsRegion", reqs: list["Requirements"], - requirements_logic_any: bool = False, ): self.address = world.location_name_to_id[name] self.loc_reqs = reqs self.sms_region = parent_region self.corona = False if not reqs else any(loc_req.corona for loc_req in reqs) - self.requirements_logic_any = requirements_logic_any if parent_region.requirements: self.corona = self.corona or any( reg_loc.corona for reg_loc in parent_region.requirements diff --git a/worlds/sms/sms_rules.py b/worlds/sms/sms_rules.py index 1cacb5204094..b643cb46bffe 100644 --- a/worlds/sms/sms_rules.py +++ b/worlds/sms/sms_rules.py @@ -2,7 +2,7 @@ from BaseClasses import Entrance, CollectionState from .sms_regions.sms_region_helper import SmsLocation, Requirements -from ..generic.Rules import set_rule, add_rule, add_item_rule +from ..generic.Rules import set_rule, add_item_rule, add_rule from .items import TICKET_ITEMS, REGULAR_PROGRESSION_ITEMS if TYPE_CHECKING: @@ -13,7 +13,6 @@ def interpret_requirements( spot: Entrance | SmsLocation, requirement_set: list[Requirements], world: "SmsWorld", - apply_requirements_any: bool = False, ) -> None: """Correctly applies and interprets custom requirements namedtuple for a given entrance/location.""" # If a region/location does not have any items required, make the section(s) return no logic. @@ -77,7 +76,7 @@ def interpret_requirements( ), current_rule=nozz_rule: current_rule(state) or state.has_all( item_set, world.player ) - req_rules.append(lambda state: nozz_rule(state)) + req_rules.append(lambda state, captured_rule=nozz_rule: captured_rule(state)) if single_req.shines and world.corona_mountain_shines > 0: # Requires X amount of shine sprites to access @@ -119,9 +118,10 @@ def interpret_requirements( ) if ( - single_req.corona - or (hasattr(spot, "corona") and spot.corona) - and world.corona_mountain_shines > 0 + world.corona_mountain_shines > 0 and ( + single_req.corona or + (hasattr(spot, "corona") and spot.corona) + ) ): # Player requires all shine sprites that are required to reach corona mountain as well. req_rules.append( @@ -134,75 +134,17 @@ def interpret_requirements( if not req_rules: continue - if apply_requirements_any: - if ( - spot.access_rule is SmsLocation.access_rule - or spot.access_rule is Entrance.access_rule - ): - set_rule( - spot, - ( - lambda state, all_rules=tuple(req_rules): any( - req_rule(state) for req_rule in all_rules - ) - ), - ) - else: - if isinstance(spot, SmsLocation): - add_rule( - spot, - ( - lambda state, all_rules=tuple(req_rules): any( - req_rule(state) for req_rule in all_rules - ) - ), - combine="or", - ) - else: - add_rule( - spot, - ( - lambda state, all_rules=tuple(req_rules): any( - req_rule(state) for req_rule in all_rules - ) - ), - ) + if spot.access_rule is SmsLocation.access_rule or spot.access_rule is Entrance.access_rule: + set_rule(spot, (lambda state, all_rules=tuple(req_rules): all(req_rule(state) for req_rule in all_rules))) else: - if ( - spot.access_rule is SmsLocation.access_rule - or spot.access_rule is Entrance.access_rule - ): - set_rule( - spot, - ( - lambda state, all_rules=tuple(req_rules): all( - req_rule(state) for req_rule in all_rules - ) - ), - ) + if isinstance(spot, SmsLocation): + add_rule(spot, (lambda state, all_rules=tuple(req_rules): + all(req_rule(state) for req_rule in req_rules)), combine="or") else: - if isinstance(spot, SmsLocation): - add_rule( - spot, - ( - lambda state, all_rules=tuple(req_rules): all( - req_rule(state) for req_rule in all_rules - ) - ), - combine="or", - ) - else: - add_rule( - spot, - ( - lambda state, all_rules=tuple(req_rules): all( - req_rule(state) for req_rule in all_rules - ) - ), - ) + add_rule(spot, + (lambda state, all_rules=tuple(req_rules): all(req_rule(state) for req_rule in req_rules))) return - def create_sms_region_and_entrance_rules(world: "SmsWorld"): for sms_reg in world.get_regions(): region_ticket: str = "" @@ -215,11 +157,14 @@ def create_sms_region_and_entrance_rules(world: "SmsWorld"): ) # If a parent region has any ticket str, get that ticket as well - if ( - hasattr(sms_entrance.parent_region, "ticket_str") + if (hasattr(sms_entrance.parent_region, "ticket_str") and sms_entrance.parent_region.ticket_str + and sms_entrance.parent_region == world.get_region( + sms_entrance.parent_region.name + ) ): region_ticket = sms_entrance.parent_region.ticket_str + break # Add the location rules within this region. for sms_loc in sms_reg.locations: @@ -228,7 +173,7 @@ def create_sms_region_and_entrance_rules(world: "SmsWorld"): interpret_requirements(sms_loc, sms_loc.loc_reqs, world) # A Region cannot have its own ticket item in ticket mode, so prevent that. - if hasattr(sms_reg, "ticket_str") or region_ticket: + if world.options.level_access.value == 1 and hasattr(sms_reg, "ticket_str") or region_ticket: reg_ticket: str = ( sms_reg.ticket_str if hasattr(sms_reg, "ticket_str") @@ -246,58 +191,16 @@ def create_sms_region_and_entrance_rules(world: "SmsWorld"): if hasattr(sms_loc, "corona") and sms_loc.corona: # Since Corona requires Spray Nozzle and Hover Nozzle to complete, ensure those items can never # be placed. Additionally, Yoshi is required for basically every late game stage. - required_nozz: list[str] = [ - "Spray Nozzle", - "Hover Nozzle", - *TICKET_ITEMS, - ] - add_item_rule( - sms_loc, - ( - lambda item, nozzles=tuple(required_nozz): item.game - != world.game - or ( - item.game == world.game - and not item.name in required_nozz - ) - ), - ) + blocked: set[str] = {"Spray Nozzle", "Hover Nozzle", *TICKET_ITEMS} # If there is a high amount of progression items, the world is too restrictive for non-macguffin # items to be placed in corona, especially with previous levels required to be beaten. if world.large_shine_count: - add_item_rule( - sms_loc, - ( - lambda item: item.game != world.game - or ( - item.game == world.game - and not item.name in REGULAR_PROGRESSION_ITEMS - ) - ), - ) + blocked |= set(REGULAR_PROGRESSION_ITEMS.keys()) - # Force Rocket to never be in Pianta Village - if "Pianta" in sms_reg.name: add_item_rule( sms_loc, - ( - lambda item: item.game != world.game - or ( - item.game == world.game and item.name != "Rocket Nozzle" - ) - ), - ) - - # Force Yoshi never to appear in Sirena 3+ - if "Sirena" in sms_reg.name and not sms_reg.name in [ - "Sirena 1 and 6", - "Sirena 2-8", - ]: - add_item_rule( - sms_loc, - ( - lambda item: item.game != world.game - or (item.game == world.game and item.name != "Yoshi") - ), + lambda item, blocked_items=frozenset(sorted(blocked)): ( + item.game != world.game or item.name not in blocked_items + ) )