mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -06:00
MLSS: Add new goal + Update basepatch to standalone equivalent (#4409)
* Item groups + small changes * Add alternate goal * New Locations and Logic Updates + Basepatch * Update basepatch.bsdiff * Update Basepatch * Update basepatch.bsdiff * Update bowsers castle logic with emblem hunt * Update Archipelago Unittests.run.xml * Update Archipelago Unittests.run.xml * Fix for overlapping ROM addresses * Update Rom.py * Update __init__.py * Update basepatch.bsdiff * Update Rom.py * Update client with new helper function * Update basepatch.bsdiff * Update worlds/mlss/__init__.py Co-authored-by: qwint <qwint.42@gmail.com> * Update worlds/mlss/__init__.py Co-authored-by: qwint <qwint.42@gmail.com> * Review Refactor * Review Refactor --------- Co-authored-by: qwint <qwint.42@gmail.com>
This commit is contained in:
@@ -269,7 +269,7 @@ class MLSSClient(BizHawkClient):
|
||||
self.local_checked_locations = locs_to_send
|
||||
|
||||
if locs_to_send is not None:
|
||||
await ctx.send_msgs([{"cmd": "LocationChecks", "locations": list(locs_to_send)}])
|
||||
await ctx.check_locations(locs_to_send)
|
||||
|
||||
except bizhawk.RequestFailedError:
|
||||
# Exit handler and return to main loop to reconnect.
|
||||
|
@@ -153,7 +153,6 @@ enemies = [
|
||||
0x50458C,
|
||||
0x5045AC,
|
||||
0x50468C,
|
||||
# 0x5046CC, 6 enemy formation
|
||||
0x5046EC,
|
||||
0x50470C
|
||||
]
|
||||
@@ -166,6 +165,7 @@ bosses = [
|
||||
0x50360C,
|
||||
0x5037AC,
|
||||
0x5037CC,
|
||||
0x50396C,
|
||||
0x503A8C,
|
||||
0x503D6C,
|
||||
0x503F0C,
|
||||
|
@@ -160,6 +160,7 @@ itemList: typing.List[ItemData] = [
|
||||
ItemData(77771142, "Game Boy Horror SP", ItemClassification.useful, 0xFE),
|
||||
ItemData(77771143, "Woo Bean", ItemClassification.skip_balancing, 0x1C),
|
||||
ItemData(77771144, "Hee Bean", ItemClassification.skip_balancing, 0x1F),
|
||||
ItemData(77771145, "Beanstar Emblem", ItemClassification.progression, 0x3E),
|
||||
]
|
||||
|
||||
item_frequencies: typing.Dict[str, int] = {
|
||||
@@ -186,5 +187,12 @@ item_frequencies: typing.Dict[str, int] = {
|
||||
"Hammers": 3,
|
||||
}
|
||||
|
||||
mlss_item_name_groups = {
|
||||
"Beanstar Piece": { "Beanstar Piece 1", "Beanstar Piece 2", "Beanstar Piece 3", "Beanstar Piece 4"},
|
||||
"Beanfruit": { "Bean Fruit 1", "Bean Fruit 2", "Bean Fruit 3", "Bean Fruit 4", "Bean Fruit 5", "Bean Fruit 6", "Bean Fruit 7"},
|
||||
"Neon Egg": { "Blue Neon Egg", "Red Neon Egg", "Green Neon Egg", "Yellow Neon Egg", "Purple Neon Egg", "Orange Neon Egg", "Azure Neon Egg"},
|
||||
"Chuckola Fruit": { "Red Chuckola Fruit", "Purple Chuckola Fruit", "White Chuckola Fruit"}
|
||||
}
|
||||
|
||||
item_table: typing.Dict[str, ItemData] = {item.itemName: item for item in itemList}
|
||||
items_by_id: typing.Dict[int, ItemData] = {item.code: item for item in itemList}
|
||||
|
@@ -251,9 +251,9 @@ coins: typing.List[LocationData] = [
|
||||
LocationData("Hoohoo Village North Cave Room 1 Coin Block", 0x39DAA0, 0),
|
||||
LocationData("Hoohoo Village South Cave Coin Block 1", 0x39DAC5, 0),
|
||||
LocationData("Hoohoo Village South Cave Coin Block 2", 0x39DAD5, 0),
|
||||
LocationData("Hoohoo Mountain Base Boo Statue Cave Coin Block 1", 0x39DAE2, 0),
|
||||
LocationData("Hoohoo Mountain Base Boo Statue Cave Coin Block 2", 0x39DAF2, 0),
|
||||
LocationData("Hoohoo Mountain Base Boo Statue Cave Coin Block 3", 0x39DAFA, 0),
|
||||
LocationData("Hoohoo Mountain Base Boostatue Cave Coin Block 1", 0x39DAE2, 0),
|
||||
LocationData("Hoohoo Mountain Base Boostatue Cave Coin Block 2", 0x39DAF2, 0),
|
||||
LocationData("Hoohoo Mountain Base Boostatue Cave Coin Block 3", 0x39DAFA, 0),
|
||||
LocationData("Beanbean Outskirts NW Coin Block", 0x39DB8F, 0),
|
||||
LocationData("Beanbean Outskirts S Room 1 Coin Block", 0x39DC18, 0),
|
||||
LocationData("Beanbean Outskirts S Room 2 Coin Block", 0x39DC3D, 0),
|
||||
@@ -262,6 +262,8 @@ coins: typing.List[LocationData] = [
|
||||
LocationData("Chucklehuck Woods Cave Room 1 Coin Block", 0x39DD7A, 0),
|
||||
LocationData("Chucklehuck Woods Cave Room 2 Coin Block", 0x39DD97, 0),
|
||||
LocationData("Chucklehuck Woods Cave Room 3 Coin Block", 0x39DDB4, 0),
|
||||
LocationData("Chucklehuck Woods Solo Luigi Cave Room 1 Coin Block 1", 0x39DB48, 0),
|
||||
LocationData("Chucklehuck Woods Solo Luigi Cave Room 1 Coin Block 2", 0x39DB50, 0),
|
||||
LocationData("Chucklehuck Woods Pipe 5 Room Coin Block", 0x39DDE6, 0),
|
||||
LocationData("Chucklehuck Woods Room 7 Coin Block", 0x39DE31, 0),
|
||||
LocationData("Chucklehuck Woods Past Chuckleroot Coin Block", 0x39DF14, 0),
|
||||
@@ -289,6 +291,7 @@ baseUltraRocks: typing.List[LocationData] = [
|
||||
LocationData("Teehee Valley Upper Maze Room 1 Block", 0x39E5E0, 0),
|
||||
LocationData("Teehee Valley Upper Maze Room 2 Digspot 1", 0x39E5C8, 0),
|
||||
LocationData("Teehee Valley Upper Maze Room 2 Digspot 2", 0x39E5D0, 0),
|
||||
LocationData("Guffawha Ruins Block", 0x39E6A3, 0),
|
||||
LocationData("Hoohoo Mountain Base Guffawha Ruins Entrance Digspot", 0x39DA0B, 0),
|
||||
LocationData("Hoohoo Mountain Base Teehee Valley Entrance Digspot", 0x39DA20, 0),
|
||||
LocationData("Hoohoo Mountain Base Teehee Valley Entrance Block", 0x39DA18, 0),
|
||||
@@ -298,7 +301,7 @@ booStatue: typing.List[LocationData] = [
|
||||
LocationData("Beanbean Outskirts Before Harhall Digspot 1", 0x39E951, 0),
|
||||
LocationData("Beanbean Outskirts Before Harhall Digspot 2", 0x39E959, 0),
|
||||
LocationData("Beanstar Piece Harhall", 0x1E9441, 2),
|
||||
LocationData("Beanbean Outskirts Boo Statue Mole", 0x1E9434, 2),
|
||||
LocationData("Beanbean Outskirts Boostatue Mole", 0x1E9434, 2),
|
||||
LocationData("Harhall's Pants", 0x1E9444, 2),
|
||||
LocationData("Beanbean Outskirts S Room 2 Digspot 1", 0x39DC65, 0),
|
||||
LocationData("Beanbean Outskirts S Room 2 Digspot 2", 0x39DC5D, 0),
|
||||
@@ -317,6 +320,9 @@ chucklehuck: typing.List[LocationData] = [
|
||||
LocationData("Chucklehuck Woods Cave Room 1 Block 2", 0x39DD8A, 0),
|
||||
LocationData("Chucklehuck Woods Cave Room 2 Block", 0x39DD9F, 0),
|
||||
LocationData("Chucklehuck Woods Cave Room 3 Block", 0x39DDAC, 0),
|
||||
LocationData("Chucklehuck Woods Solo Luigi Cave Room 2 Block", 0x39DB72, 0),
|
||||
LocationData("Chucklehuck Woods Solo Luigi Cave Room 3 Block 1", 0x39DB5D, 0),
|
||||
LocationData("Chucklehuck Woods Solo Luigi Cave Room 3 Block 2", 0x39DB65, 0),
|
||||
LocationData("Chucklehuck Woods Room 2 Block", 0x39DDC1, 0),
|
||||
LocationData("Chucklehuck Woods Room 2 Digspot", 0x39DDC9, 0),
|
||||
LocationData("Chucklehuck Woods Pipe Room Block 1", 0x39DDD6, 0),
|
||||
@@ -786,7 +792,7 @@ nonBlock = [
|
||||
(0x4373, 0x10, 0x277A45), # Teehee Valley Mole
|
||||
(0x434D, 0x8, 0x1E9444), # Harhall's Pants
|
||||
(0x432E, 0x10, 0x1E9441), # Harhall Beanstar Piece
|
||||
(0x434B, 0x8, 0x1E9434), # Outskirts Boo Statue Mole
|
||||
(0x434B, 0x8, 0x1E9434), # Outskirts Boostatue Mole
|
||||
(0x42FE, 0x2, 0x1E943E), # Red Goblet
|
||||
(0x42FE, 0x4, 0x24E628), # Green Goblet
|
||||
(0x4301, 0x10, 0x250621), # Red Chuckola Fruit
|
||||
|
@@ -59,7 +59,7 @@ class LocationName:
|
||||
HoohooMountainBaseBoostatueRoomDigspot1 = "Hoohoo Mountain Base Boostatue Room Digspot 1"
|
||||
HoohooMountainBaseBoostatueRoomDigspot2 = "Hoohoo Mountain Base Boostatue Room Digspot 2"
|
||||
HoohooMountainBaseBoostatueRoomDigspot3 = "Hoohoo Mountain Base Boostatue Room Digspot 3"
|
||||
BeanbeanOutskirtsBooStatueMole = "Beanbean Outskirts Boo Statue Mole"
|
||||
BeanbeanOutskirtsBooStatueMole = "Beanbean Outskirts Boostatue Mole"
|
||||
HoohooMountainBaseGrassyAreaBlock1 = "Hoohoo Mountain Base Grassy Area Block 1"
|
||||
HoohooMountainBaseGrassyAreaBlock2 = "Hoohoo Mountain Base Grassy Area Block 2"
|
||||
HoohooMountainBaseGuffawhaRuinsEntranceDigspot = "Hoohoo Mountain Base Guffawha Ruins Entrance Digspot"
|
||||
@@ -533,9 +533,9 @@ class LocationName:
|
||||
BadgeShopMomPiranhaFlag2 = "Badge Shop Mom Piranha Flag 2"
|
||||
BadgeShopMomPiranhaFlag3 = "Badge Shop Mom Piranha Flag 3"
|
||||
HarhallsPants = "Harhall's Pants"
|
||||
HoohooMountainBaseBooStatueCaveCoinBlock1 = "Hoohoo Mountain Base Boo Statue Cave Coin Block 1"
|
||||
HoohooMountainBaseBooStatueCaveCoinBlock2 = "Hoohoo Mountain Base Boo Statue Cave Coin Block 2"
|
||||
HoohooMountainBaseBooStatueCaveCoinBlock3 = "Hoohoo Mountain Base Boo Statue Cave Coin Block 3"
|
||||
HoohooMountainBaseBooStatueCaveCoinBlock1 = "Hoohoo Mountain Base Boostatue Cave Coin Block 1"
|
||||
HoohooMountainBaseBooStatueCaveCoinBlock2 = "Hoohoo Mountain Base Boostatue Cave Coin Block 2"
|
||||
HoohooMountainBaseBooStatueCaveCoinBlock3 = "Hoohoo Mountain Base Boostatue Cave Coin Block 3"
|
||||
BeanbeanOutskirtsNWCoinBlock = "Beanbean Outskirts NW Coin Block"
|
||||
BeanbeanOutskirtsSRoom1CoinBlock = "Beanbean Outskirts S Room 1 Coin Block"
|
||||
BeanbeanOutskirtsSRoom2CoinBlock = "Beanbean Outskirts S Room 2 Coin Block"
|
||||
|
@@ -2,13 +2,13 @@ from Options import Choice, Toggle, StartInventoryPool, PerGameCommonOptions, Ra
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
class BowsersCastleSkip(Toggle):
|
||||
class SkipBowsersCastle(Toggle):
|
||||
"""
|
||||
Skip straight from the entrance hall to Bowletta in Bowser's Castle.
|
||||
Skip straight from the Entrance Hall to Bowletta in Bowser's Castle.
|
||||
All Bowser's Castle locations will be removed from the location pool.
|
||||
"""
|
||||
|
||||
display_name = "Bowser's Castle Skip"
|
||||
display_name = "Skip Bowser's Castle"
|
||||
|
||||
|
||||
class ExtraPipes(Toggle):
|
||||
@@ -272,13 +272,47 @@ class ChuckleBeans(Choice):
|
||||
option_all = 2
|
||||
default = 2
|
||||
|
||||
class Goal(Choice):
|
||||
"""
|
||||
Vanilla: Complete jokes end with the required items and defeat Birdo to unlock Bowser's Castle.
|
||||
|
||||
Emblem Hunt: Find the required number of Beanstar Emblems to gain access to Bowser's Castle.
|
||||
"""
|
||||
display_name = "Goal"
|
||||
option_vanilla = 0
|
||||
option_emblem_hunt = 1
|
||||
default = 0
|
||||
|
||||
class EmblemsRequired(Range):
|
||||
"""
|
||||
Number of Beanstar Emblems to collect to unlock Bowser's Castle.
|
||||
|
||||
If Goal is not Emblem Hunt, this does nothing.
|
||||
"""
|
||||
display_name = "Emblems Required"
|
||||
range_start = 1
|
||||
range_end = 100
|
||||
default = 50
|
||||
|
||||
|
||||
class EmblemsAmount(Range):
|
||||
"""
|
||||
Number of Beanstar Emblems that are in the pool.
|
||||
|
||||
If Goal is not Emblem Hunt, this does nothing.
|
||||
"""
|
||||
display_name = "Emblems Available"
|
||||
range_start = 1
|
||||
range_end = 150
|
||||
default = 75
|
||||
|
||||
|
||||
@dataclass
|
||||
class MLSSOptions(PerGameCommonOptions):
|
||||
start_inventory_from_pool: StartInventoryPool
|
||||
coins: Coins
|
||||
difficult_logic: DifficultLogic
|
||||
castle_skip: BowsersCastleSkip
|
||||
castle_skip: SkipBowsersCastle
|
||||
extra_pipes: ExtraPipes
|
||||
skip_minecart: SkipMinecart
|
||||
disable_surf: DisableSurf
|
||||
@@ -286,6 +320,9 @@ class MLSSOptions(PerGameCommonOptions):
|
||||
harhalls_pants: Removed
|
||||
block_visibility: HiddenVisible
|
||||
chuckle_beans: ChuckleBeans
|
||||
goal: Goal
|
||||
emblems_required: EmblemsRequired
|
||||
emblems_amount: EmblemsAmount
|
||||
music_options: MusicOptions
|
||||
randomize_sounds: RandomSounds
|
||||
randomize_enemies: RandomizeEnemies
|
||||
|
@@ -91,6 +91,16 @@ def connect_regions(world: "MLSSWorld"):
|
||||
connect(world, names, "Main Area", "BaseUltraRocks", lambda state: StateLogic.ultra(state, world.player))
|
||||
connect(world, names, "Main Area", "Chucklehuck Woods", lambda state: StateLogic.brooch(state, world.player))
|
||||
connect(world, names, "Main Area", "BooStatue", lambda state: StateLogic.canCrash(state, world.player))
|
||||
if world.options.goal == "emblem_hunt":
|
||||
if world.options.castle_skip:
|
||||
connect(world, names, "Main Area", "Cackletta's Soul",
|
||||
lambda state: state.has("Beanstar Emblem", world.player, world.options.emblems_required.value))
|
||||
else:
|
||||
connect(world, names, "Main Area", "Bowser's Castle", lambda state: state.has("Beanstar Emblem", world.player, world.options.emblems_required.value))
|
||||
connect(world, names, "Bowser's Castle", "Bowser's Castle Mini", lambda state:
|
||||
StateLogic.canMini(state, world.player)
|
||||
and StateLogic.thunder(state,world.player))
|
||||
connect(world, names, "Bowser's Castle Mini", "Cackletta's Soul", lambda state: StateLogic.soul(state, world.player))
|
||||
connect(
|
||||
world,
|
||||
names,
|
||||
@@ -213,8 +223,8 @@ def connect_regions(world: "MLSSWorld"):
|
||||
connect(world, names, "Surfable", "GwarharEntrance")
|
||||
connect(world, names, "Surfable", "Oasis")
|
||||
connect(world, names, "Surfable", "JokesEntrance", lambda state: StateLogic.fire(state, world.player))
|
||||
connect(world, names, "JokesMain", "PostJokes", lambda state: StateLogic.postJokes(state, world.player))
|
||||
if not world.options.castle_skip:
|
||||
connect(world, names, "JokesMain", "PostJokes", lambda state: StateLogic.postJokes(state, world.player, world.options.goal.value))
|
||||
if not world.options.castle_skip and world.options.goal != "emblem_hunt":
|
||||
connect(world, names, "PostJokes", "Bowser's Castle")
|
||||
connect(
|
||||
world,
|
||||
@@ -224,7 +234,7 @@ def connect_regions(world: "MLSSWorld"):
|
||||
lambda state: StateLogic.canMini(state, world.player) and StateLogic.thunder(state, world.player),
|
||||
)
|
||||
connect(world, names, "Bowser's Castle Mini", "Cackletta's Soul")
|
||||
else:
|
||||
elif world.options.goal != "emblem_hunt":
|
||||
connect(world, names, "PostJokes", "Cackletta's Soul")
|
||||
connect(world, names, "Chucklehuck Woods", "Winkle", lambda state: StateLogic.canDash(state, world.player))
|
||||
connect(
|
||||
@@ -247,14 +257,14 @@ def connect_regions(world: "MLSSWorld"):
|
||||
names,
|
||||
"Shop Starting Flag",
|
||||
"Shop Birdo Flag",
|
||||
lambda state: StateLogic.postJokes(state, world.player),
|
||||
lambda state: StateLogic.postJokes(state, world.player, world.options.goal.value),
|
||||
)
|
||||
connect(
|
||||
world,
|
||||
names,
|
||||
"Fungitown",
|
||||
"Fungitown Shop Birdo Flag",
|
||||
lambda state: StateLogic.postJokes(state, world.player),
|
||||
lambda state: StateLogic.postJokes(state, world.player, world.options.goal.value),
|
||||
)
|
||||
else:
|
||||
connect(
|
||||
@@ -276,14 +286,14 @@ def connect_regions(world: "MLSSWorld"):
|
||||
names,
|
||||
"Shop Starting Flag",
|
||||
"Shop Birdo Flag",
|
||||
lambda state: StateLogic.canCrash(state, world.player) and StateLogic.postJokes(state, world.player),
|
||||
lambda state: StateLogic.canCrash(state, world.player) and StateLogic.postJokes(state, world.player, world.options.goal.value),
|
||||
)
|
||||
connect(
|
||||
world,
|
||||
names,
|
||||
"Fungitown",
|
||||
"Fungitown Shop Birdo Flag",
|
||||
lambda state: StateLogic.canCrash(state, world.player) and StateLogic.postJokes(state, world.player),
|
||||
lambda state: StateLogic.canCrash(state, world.player) and StateLogic.postJokes(state, world.player, world.options.goal.value),
|
||||
)
|
||||
|
||||
|
||||
|
@@ -177,10 +177,10 @@ class MLSSPatchExtension(APPatchExtension):
|
||||
for pos in enemies:
|
||||
stream.seek(pos + 8)
|
||||
for _ in range(6):
|
||||
enemy = int.from_bytes(stream.read(1))
|
||||
enemy = int.from_bytes(stream.read(1), "little")
|
||||
if enemy > 0:
|
||||
stream.seek(1, 1)
|
||||
flag = int.from_bytes(stream.read(1))
|
||||
flag = int.from_bytes(stream.read(1), "little")
|
||||
if flag == 0x7:
|
||||
break
|
||||
if flag in [0x0, 0x2, 0x4]:
|
||||
@@ -196,12 +196,12 @@ class MLSSPatchExtension(APPatchExtension):
|
||||
stream.seek(pos + 8)
|
||||
|
||||
for _ in range(6):
|
||||
enemy = int.from_bytes(stream.read(1))
|
||||
enemy = int.from_bytes(stream.read(1), "little")
|
||||
if enemy > 0 and enemy not in Data.flying and enemy not in Data.pestnut:
|
||||
if enemy == 0x52:
|
||||
chomp = True
|
||||
stream.seek(1, 1)
|
||||
flag = int.from_bytes(stream.read(1))
|
||||
flag = int.from_bytes(stream.read(1), "little")
|
||||
if flag not in [0x0, 0x2, 0x4]:
|
||||
stream.seek(1, 1)
|
||||
continue
|
||||
@@ -234,7 +234,7 @@ class MLSSPatchExtension(APPatchExtension):
|
||||
stream.seek(pos)
|
||||
temp = stream.read(1)
|
||||
stream.seek(pos)
|
||||
stream.write(bytes([temp[0] | 0x8]))
|
||||
stream.write(bytes([temp[0] | 0x80]))
|
||||
stream.seek(pos + 1)
|
||||
stream.write(groups.pop())
|
||||
|
||||
@@ -316,6 +316,10 @@ def write_tokens(world: "MLSSWorld", patch: MLSSProcedurePatch) -> None:
|
||||
|
||||
patch.write_token(APTokenTypes.WRITE, 0xD00003, bytes([world.options.xp_multiplier.value]))
|
||||
|
||||
if world.options.goal == 1:
|
||||
patch.write_token(APTokenTypes.WRITE, 0xD00008, bytes([world.options.goal.value]))
|
||||
patch.write_token(APTokenTypes.WRITE, 0xD00009, bytes([world.options.emblems_required.value]))
|
||||
|
||||
if world.options.tattle_hp:
|
||||
patch.write_token(APTokenTypes.WRITE, 0xD00000, bytes([0x1]))
|
||||
|
||||
@@ -427,4 +431,4 @@ def desc_inject(world: "MLSSWorld", patch: MLSSProcedurePatch, location: Locatio
|
||||
index = value.index(location.address) + 66
|
||||
|
||||
dstring = f"{world.multiworld.player_name[item.player]}: {item.name}"
|
||||
patch.write_token(APTokenTypes.WRITE, 0xD11000 + (index * 0x40), dstring.encode("UTF8"))
|
||||
patch.write_token(APTokenTypes.WRITE, 0xD12000 + (index * 0x40), dstring.encode("UTF8"))
|
||||
|
@@ -28,11 +28,14 @@ def set_rules(world: "MLSSWorld", excluded):
|
||||
lambda state: StateLogic.canDig(state, world.player),
|
||||
)
|
||||
if "Shop" in location.name and "Coffee" not in location.name and location.name not in excluded:
|
||||
forbid_item(world.get_location(location.name), "Hammers", world.player)
|
||||
if "Badge" in location.name or "Pants" in location.name:
|
||||
add_rule(
|
||||
world.get_location(location.name),
|
||||
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
|
||||
lambda state: (StateLogic.brooch(state, world.player) and StateLogic.fruits(state, world.player)
|
||||
and (StateLogic.hammers(state, world.player)
|
||||
or StateLogic.fire(state, world.player)
|
||||
or StateLogic.thunder(state, world.player)))
|
||||
or StateLogic.rose(state, world.player),
|
||||
)
|
||||
if location.itemType != 0 and location.name not in excluded:
|
||||
if "Bowser" in location.name and world.options.castle_skip:
|
||||
@@ -99,9 +102,86 @@ def set_rules(world: "MLSSWorld", excluded):
|
||||
lambda state: StateLogic.ultra(state, world.player) and StateLogic.thunder(state, world.player),
|
||||
)
|
||||
|
||||
forbid_item(
|
||||
world.get_location(LocationName.SSChuckolaMembershipCard), "Nuts", world.player
|
||||
) # Bandaid Fix
|
||||
if world.options.goal == 1 and not world.options.castle_skip:
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleRoyCorridorBlock1),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleRoyCorridorBlock2),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleMiniMarioSidescrollerBlock1),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleMiniMarioSidescrollerBlock2),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleMiniMarioMazeBlock1),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleMiniMarioMazeBlock2),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleBeforeWendyFightBlock1),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
and StateLogic.ultra(state, world.player)
|
||||
and StateLogic.fire(state, world.player)
|
||||
and StateLogic.canCrash(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleBeforeWendyFightBlock2),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
and StateLogic.ultra(state, world.player)
|
||||
and StateLogic.fire(state, world.player)
|
||||
and StateLogic.canCrash(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleLarryRoomBlock),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
and StateLogic.ultra(state, world.player)
|
||||
and StateLogic.canDash(state, world.player)
|
||||
and StateLogic.canCrash(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleWendyLarryHallwayDigspot),
|
||||
lambda state: StateLogic.ultra(state, world.player)
|
||||
and StateLogic.fire(state, world.player)
|
||||
and StateLogic.canCrash(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleBeforeFawfulFightBlock1),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
and StateLogic.ultra(state, world.player)
|
||||
and StateLogic.canDash(state, world.player)
|
||||
and StateLogic.canCrash(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleBeforeFawfulFightBlock2),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
and StateLogic.ultra(state, world.player)
|
||||
and StateLogic.canDash(state, world.player)
|
||||
and StateLogic.canCrash(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleGreatDoorBlock1),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
and StateLogic.ultra(state, world.player)
|
||||
and StateLogic.canDash(state, world.player)
|
||||
and StateLogic.canCrash(state, world.player)
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.BowsersCastleGreatDoorBlock2),
|
||||
lambda state: StateLogic.canDig(state, world.player)
|
||||
and StateLogic.ultra(state, world.player)
|
||||
and StateLogic.canDash(state, world.player)
|
||||
and StateLogic.canCrash(state, world.player)
|
||||
)
|
||||
|
||||
add_rule(
|
||||
world.get_location(LocationName.HoohooVillageHammerHouseBlock),
|
||||
@@ -398,6 +478,10 @@ def set_rules(world: "MLSSWorld", excluded):
|
||||
world.get_location(LocationName.BeanstarPieceWinkleArea),
|
||||
lambda state: StateLogic.winkle(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location("Guffawha Ruins Block"),
|
||||
lambda state: StateLogic.thunder(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.GwarharLagoonSpangleReward),
|
||||
lambda state: StateLogic.spangle(state, world.player),
|
||||
@@ -406,6 +490,18 @@ def set_rules(world: "MLSSWorld", excluded):
|
||||
world.get_location(LocationName.PantsShopMomPiranhaFlag1),
|
||||
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location("Chucklehuck Woods Solo Luigi Cave Room 2 Block"),
|
||||
lambda state: StateLogic.brooch(state, world.player) and StateLogic.canDig(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location("Chucklehuck Woods Solo Luigi Cave Room 3 Block 1"),
|
||||
lambda state: StateLogic.brooch(state, world.player) and StateLogic.canDig(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location("Chucklehuck Woods Solo Luigi Cave Room 3 Block 2"),
|
||||
lambda state: StateLogic.brooch(state, world.player) and StateLogic.canDig(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.PantsShopMomPiranhaFlag2),
|
||||
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
|
||||
@@ -600,6 +696,14 @@ def set_rules(world: "MLSSWorld", excluded):
|
||||
world.get_location(LocationName.HoohooMountainBaseBooStatueCaveCoinBlock1),
|
||||
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location("Chucklehuck Woods Solo Luigi Cave Room 1 Coin Block 1"),
|
||||
lambda state: StateLogic.canDig(state, world.player) and StateLogic.brooch(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location("Chucklehuck Woods Solo Luigi Cave Room 1 Coin Block 2"),
|
||||
lambda state: StateLogic.canDig(state, world.player) and StateLogic.brooch(state, world.player),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.HoohooMountainBaseBooStatueCaveCoinBlock2),
|
||||
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
|
||||
@@ -679,7 +783,7 @@ def set_rules(world: "MLSSWorld", excluded):
|
||||
add_rule(
|
||||
world.get_location(LocationName.GwarharLagoonFirstUnderwaterAreaRoom2CoinBlock),
|
||||
lambda state: StateLogic.canDash(state, world.player)
|
||||
and (StateLogic.membership(state, world.player) or StateLogic.surfable(state, world.player)),
|
||||
and (StateLogic.membership(state, world.player) or StateLogic.surfable(state, world.player)),
|
||||
)
|
||||
add_rule(
|
||||
world.get_location(LocationName.JokesEndSecondFloorWestRoomCoinBlock),
|
||||
|
@@ -1,3 +1,6 @@
|
||||
from .Options import Goal
|
||||
|
||||
|
||||
def canDig(state, player):
|
||||
return state.has("Green Goblet", player) and state.has("Hammers", player)
|
||||
|
||||
@@ -105,8 +108,9 @@ def surfable(state, player):
|
||||
)
|
||||
|
||||
|
||||
def postJokes(state, player):
|
||||
return (
|
||||
def postJokes(state, player, goal):
|
||||
if goal == Goal.option_vanilla: # Logic for beating jokes end without beanstar emblems
|
||||
return (
|
||||
surfable(state, player)
|
||||
and canDig(state, player)
|
||||
and dressBeanstar(state, player)
|
||||
@@ -115,7 +119,13 @@ def postJokes(state, player):
|
||||
and brooch(state, player)
|
||||
and rose(state, player)
|
||||
and canDash(state, player)
|
||||
)
|
||||
)
|
||||
else: # Logic for beating jokes end with beanstar emblems
|
||||
return (
|
||||
surfable(state, player)
|
||||
and canDig(state, player)
|
||||
and canDash(state, player)
|
||||
)
|
||||
|
||||
|
||||
def teehee(state, player):
|
||||
@@ -153,3 +163,10 @@ def birdo_shop(state, player):
|
||||
|
||||
def fungitown_birdo_shop(state, player):
|
||||
return state.can_reach("Fungitown Shop Birdo Flag", "Region", player)
|
||||
|
||||
def soul(state, player):
|
||||
return (ultra(state, player)
|
||||
and canMini(state, player)
|
||||
and canDig(state, player)
|
||||
and canDash(state, player)
|
||||
and canCrash(state, player))
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
import os
|
||||
import pkgutil
|
||||
import typing
|
||||
@@ -7,7 +8,7 @@ from worlds.AutoWorld import WebWorld, World
|
||||
from typing import Set, Dict, Any
|
||||
from .Locations import all_locations, location_table, bowsers, bowsersMini, hidden, coins
|
||||
from .Options import MLSSOptions
|
||||
from .Items import MLSSItem, itemList, item_frequencies, item_table
|
||||
from .Items import MLSSItem, itemList, item_frequencies, item_table, mlss_item_name_groups
|
||||
from .Names.LocationName import LocationName
|
||||
from .Client import MLSSClient
|
||||
from .Regions import create_regions, connect_regions
|
||||
@@ -53,6 +54,7 @@ class MLSSWorld(World):
|
||||
options_dataclass = MLSSOptions
|
||||
options: MLSSOptions
|
||||
settings: typing.ClassVar[MLSSSettings]
|
||||
item_name_groups = mlss_item_name_groups
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = {loc_data.name: loc_data.id for loc_data in all_locations}
|
||||
required_client_version = (0, 5, 0)
|
||||
@@ -61,6 +63,12 @@ class MLSSWorld(World):
|
||||
|
||||
def generate_early(self) -> None:
|
||||
self.disabled_locations = set()
|
||||
if self.options.goal == "emblem_hunt":
|
||||
if self.options.emblems_amount < self.options.emblems_required:
|
||||
self.options.emblems_amount.value = self.options.emblems_required.value
|
||||
logging.warning(
|
||||
f"{self.player_name}'s number of emblems required is greater than the number of emblems available. "
|
||||
f"Changing to {self.options.emblems_required.value}.")
|
||||
if self.options.skip_minecart:
|
||||
self.disabled_locations.update([LocationName.HoohooMountainBaseMinecartCaveDigspot])
|
||||
if self.options.disable_surf:
|
||||
@@ -111,6 +119,8 @@ class MLSSWorld(World):
|
||||
for item in itemList:
|
||||
if item.classification != ItemClassification.filler and item.classification != ItemClassification.skip_balancing:
|
||||
freq = item_frequencies.get(item.itemName, 1)
|
||||
if item.itemName == "Beanstar Emblem":
|
||||
freq = (0 if self.options.goal != "emblem_hunt" else self.options.emblems_amount.value)
|
||||
if item in precollected:
|
||||
freq = max(freq - precollected.count(item), 0)
|
||||
if self.options.disable_harhalls_pants and "Harhall's" in item.itemName:
|
||||
@@ -138,7 +148,6 @@ class MLSSWorld(World):
|
||||
|
||||
# And finally take as many fillers as we need to have the same amount of items and locations.
|
||||
remaining = len(all_locations) - len(required_items) - len(self.disabled_locations) - 5
|
||||
|
||||
self.multiworld.itempool += [
|
||||
self.create_item(filler_item_name) for filler_item_name in self.random.sample(filler_items, remaining)
|
||||
]
|
||||
|
Binary file not shown.
Reference in New Issue
Block a user