Skip to content
Open
4 changes: 1 addition & 3 deletions worlds/sms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ class SmsWorld(World):
game = "Super Mario Sunshine"
web = SmsWebWorld()

data_version = 1

options_dataclass = SmsOptions
options: SmsOptions

Expand Down Expand Up @@ -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

Expand Down
2 changes: 0 additions & 2 deletions worlds/sms/regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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(
Expand Down
3 changes: 0 additions & 3 deletions worlds/sms/sms_regions/sms_region_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,18 @@ class SmsLocation(Location):
sms_region: "SmsRegion"
loc_reqs: list["Requirements"]
corona: bool
requirements_logic_any: bool

def __init__(
self,
world: "SmsWorld",
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
Expand Down
145 changes: 24 additions & 121 deletions worlds/sms/sms_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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 = ""
Expand All @@ -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:
Expand All @@ -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")
Expand All @@ -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
)
)
Loading