Mario & Luigi: Superstar Saga: Implement New Game (#2754)

* Commit for PR

* Commit for PR

* Update worlds/mlss/Client.py

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Update worlds/mlss/__init__.py

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Update worlds/mlss/__init__.py

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Update worlds/mlss/docs/setup_en.md

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>

* Remove deprecated import. Updated settings and romfile syntax

* Updated Options to new system. Changed all references from MultiWorld to World

* Changed switch statements to if else

* Update en_Mario & Luigi Superstar Saga.md

* Updated client.py

* Update Client.py

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Updated logic, Updated patch implementation, Removed unused imports, Cleaned up Code

* Update __init__.py

* Changed reference from world to mlssworld

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>

* Fix merge conflict + update prep

* v1.2

* Leftover print commands

* Update basepatch.bsdiff

* Update basepatch.bsdiff

* v1.3

* Update Rom.py

* Change tracker locations to serverside, no longer locations. Various code cleanup and logic changes.

* Event removal continuation.

* Partial Implementation of APPP (Incomplete))

* v1.4 Implemented APPP

* Docs Updated

* Update Rom.py

* Update setup_en.md

* Update Rom.py

* Update Rules.py

* Fix for APPP being broken on webhost

* Update Rom.py

* Update Rom.py

* Location name fixes + pants color fixes

* Update Rules.py

* Fix for ultra hammer cutscene

* Fixed compat. issues with python ver. 3.8

* Updated hidden block yaml option

* pre-v1.5

* Update Client.py

* Update basepatch.bsdiff

* v1.5

* Update XP multiplier to have a minimum of 0

* Update 'Beanfruit' to 'Bean Fruit'

* v1.6

* Update Rom.py

* Update basepatch.bsdiff

* Initial review refactor

* Revert state logic changes. Continuation of refactor.

* Fixed failed generations. Finished refactor.

* Reworked colors. Removed all .txt files

* Actually removed the .txt files this time

* Update Rom.py

* Update README.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Options.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Client.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/__init__.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Data.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Review refactor.

* Update README.md

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Update worlds/mlss/Rules.py

Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>

* Add coin blocks to LocationName

* Refactor.

* Update Items.py

* Delete mlss.apworld

* Small asm bugfix

* Update basepatch.bsdiff

* Client sends less messages to server

* Update basepatch.bsdiff

---------

Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com>
Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
This commit is contained in:
jamesbrq 2024-05-06 03:15:06 -04:00 committed by GitHub
parent 2aa3ef372d
commit 5935093615
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 10027 additions and 0 deletions

View File

@ -65,6 +65,7 @@ Currently, the following games are supported:
* Castlevania 64
* A Short Hike
* Yoshi's Island
* Mario & Luigi: Superstar Saga
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled

View File

@ -92,6 +92,9 @@
/worlds/lufia2ac/ @el-u
/worlds/lufia2ac/docs/ @wordfcuk @el-u
# Mario & Luigi: Superstar Saga
/worlds/mlss/ @jamesbrq
# Meritous
/worlds/meritous/ @FelicitusNeko

297
worlds/mlss/Client.py Normal file
View File

@ -0,0 +1,297 @@
from typing import TYPE_CHECKING, Optional, Set, List, Dict
import struct
from NetUtils import ClientStatus
from .Locations import roomCount, nonBlock, beanstones, roomException, shop, badge, pants, eReward
from .Items import items_by_id
import asyncio
import worlds._bizhawk as bizhawk
from worlds._bizhawk.client import BizHawkClient
if TYPE_CHECKING:
from worlds._bizhawk.context import BizHawkClientContext
ROOM_ARRAY_POINTER = 0x51FA00
class MLSSClient(BizHawkClient):
game = "Mario & Luigi Superstar Saga"
system = "GBA"
patch_suffix = ".apmlss"
local_checked_locations: Set[int]
goal_flag: int
rom_slot_name: Optional[str]
eUsed: List[int]
room: int
local_events: List[int]
player_name: Optional[str]
checked_flags: Dict[int, list] = {}
def __init__(self) -> None:
super().__init__()
self.local_checked_locations = set()
self.local_set_events = {}
self.local_found_key_items = {}
self.rom_slot_name = None
self.seed_verify = False
self.eUsed = []
self.room = 0
self.local_events = []
async def validate_rom(self, ctx: "BizHawkClientContext") -> bool:
from CommonClient import logger
try:
# Check ROM name/patch version
rom_name_bytes = await bizhawk.read(ctx.bizhawk_ctx, [(0xA0, 14, "ROM")])
rom_name = bytes([byte for byte in rom_name_bytes[0] if byte != 0]).decode("UTF-8")
if not rom_name.startswith("MARIO&LUIGIU"):
return False
if rom_name == "MARIO&LUIGIUA8":
logger.info(
"ERROR: You appear to be running an unpatched version of Mario & Luigi Superstar Saga. "
"You need to generate a patch file and use it to create a patched ROM."
)
return False
if rom_name != "MARIO&LUIGIUAP":
logger.info(
"ERROR: The patch file used to create this ROM is not compatible with "
"this client. Double check your client version against the version being "
"used by the generator."
)
return False
except UnicodeDecodeError:
return False
except bizhawk.RequestFailedError:
return False # Should verify on the next pass
ctx.game = self.game
ctx.items_handling = 0b101
ctx.want_slot_data = True
ctx.watcher_timeout = 0.125
self.rom_slot_name = rom_name
self.seed_verify = False
name_bytes = (await bizhawk.read(ctx.bizhawk_ctx, [(0xDF0000, 16, "ROM")]))[0]
name = bytes([byte for byte in name_bytes if byte != 0]).decode("UTF-8")
self.player_name = name
for i in range(59):
self.checked_flags[i] = []
return True
async def set_auth(self, ctx: "BizHawkClientContext") -> None:
ctx.auth = self.player_name
def on_package(self, ctx, cmd, args) -> None:
if cmd == "RoomInfo":
ctx.seed_name = args["seed_name"]
async def game_watcher(self, ctx: "BizHawkClientContext") -> None:
from CommonClient import logger
try:
if ctx.seed_name is None:
return
if not self.seed_verify:
seed = await bizhawk.read(ctx.bizhawk_ctx, [(0xDF00A0, len(ctx.seed_name), "ROM")])
seed = seed[0].decode("UTF-8")
if seed != ctx.seed_name:
logger.info(
"ERROR: The ROM you loaded is for a different game of AP. "
"Please make sure the host has sent you the correct patch file,"
"and that you have opened the correct ROM."
)
raise bizhawk.ConnectorError("Loaded ROM is for Incorrect lobby.")
self.seed_verify = True
read_state = await bizhawk.read(
ctx.bizhawk_ctx,
[
(0x4564, 59, "EWRAM"),
(0x2330, 2, "IWRAM"),
(0x3FE0, 1, "IWRAM"),
(0x304A, 1, "EWRAM"),
(0x304B, 1, "EWRAM"),
(0x304C, 4, "EWRAM"),
(0x3060, 6, "EWRAM"),
(0x4808, 2, "EWRAM"),
(0x4407, 1, "EWRAM"),
(0x2339, 1, "IWRAM"),
]
)
flags = read_state[0]
current_room = int.from_bytes(read_state[1], "little")
shop_init = read_state[2][0]
shop_scroll = read_state[3][0] & 0x1F
is_buy = read_state[4][0] != 0
shop_address = (struct.unpack("<I", read_state[5])[0]) & 0xFFFFFF
logo = bytes([byte for byte in read_state[6] if byte < 0x70]).decode("UTF-8")
received_index = (read_state[7][0] << 8) + read_state[7][1]
cackletta = read_state[8][0] & 0x40
shopping = read_state[9][0] & 0xF
if logo != "MLSSAP":
return
locs_to_send = set()
# Checking shop purchases
if is_buy:
await bizhawk.write(ctx.bizhawk_ctx, [(0x304A, [0x0, 0x0], "EWRAM")])
if shop_address != 0x3C0618 and shop_address != 0x3C0684:
location = shop[shop_address][shop_scroll]
else:
if shop_init & 0x1 != 0:
location = badge[shop_address][shop_scroll]
else:
location = pants[shop_address][shop_scroll]
if location in ctx.server_locations:
locs_to_send.add(location)
# Loop for receiving items. Item is written as an ID into 0x3057.
# ASM reads the ID in a loop and give the player the item before resetting the RAM address to 0x0.
# If RAM address isn't 0x0 yet break out and try again later to give the rest of the items
for i in range(len(ctx.items_received) - received_index):
item_data = items_by_id[ctx.items_received[received_index + i].item]
b = await bizhawk.guarded_read(ctx.bizhawk_ctx, [(0x3057, 1, "EWRAM")], [(0x3057, [0x0], "EWRAM")])
if b is None:
break
await bizhawk.write(
ctx.bizhawk_ctx,
[
(0x3057, [id_to_RAM(item_data.itemID)], "EWRAM"),
(0x4808, [(received_index + i + 1) // 0x100, (received_index + i + 1) % 0x100], "EWRAM"),
],
)
await asyncio.sleep(0.1)
# Early return and location send if you are currently in a shop,
# since other flags aren't going to change
if shopping & 0x3 == 0x3:
if locs_to_send != self.local_checked_locations:
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)}])
return
# Checking flags that aren't digspots or blocks
for item in nonBlock:
address, mask, location = item
if location in self.local_checked_locations:
continue
flag_bytes = await bizhawk.read(ctx.bizhawk_ctx, [(address, 1, "EWRAM"), (0x3060, 6, "EWRAM")])
flag_byte = flag_bytes[0][0]
backup_logo = bytes([byte for byte in flag_bytes[1] if byte < 0x70]).decode("UTF-8")
if backup_logo != "MLSSAP":
return
if flag_byte & mask != 0:
if location >= 0xDA0000 and location not in self.local_events:
self.local_events += [location]
await ctx.send_msgs(
[
{
"cmd": "Set",
"key": f"mlss_flag_{ctx.team}_{ctx.slot}",
"default": 0,
"want_reply": False,
"operations": [{"operation": "or", "value": 1 << (location - 0xDA0000)}],
}
]
)
continue
if location in roomException:
if current_room not in roomException[location]:
exception = True
else:
exception = False
else:
exception = True
if location in eReward:
if location not in self.eUsed:
self.eUsed += [location]
location = eReward[len(self.eUsed) - 1]
else:
continue
if (location in ctx.server_locations) and exception:
locs_to_send.add(location)
# Check for set location flags.
for byte_i, byte in enumerate(bytearray(flags)):
for j in range(8):
if j in self.checked_flags[byte_i]:
continue
and_value = 1 << j
if byte & and_value != 0:
flag_id = byte_i * 8 + (j + 1)
room, item = find_key(roomCount, flag_id)
pointer_arr = await bizhawk.read(
ctx.bizhawk_ctx, [(ROOM_ARRAY_POINTER + ((room - 1) * 4), 4, "ROM")]
)
pointer = struct.unpack("<I", pointer_arr[0])[0]
pointer = pointer & 0xFFFFFF
offset = await bizhawk.read(ctx.bizhawk_ctx, [(pointer, 1, "ROM")])
offset = offset[0][0]
if offset != 0:
offset = 2
pointer += (item * 8) + 1 + offset
for key, value in beanstones.items():
if pointer == value:
pointer = key
break
if pointer in ctx.server_locations:
self.checked_flags[byte_i] += [j]
locs_to_send.add(pointer)
if not ctx.finished_game and cackletta != 0 and current_room == 0x1C7:
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
if self.room != current_room:
self.room = current_room
await ctx.send_msgs(
[
{
"cmd": "Set",
"key": f"mlss_room_{ctx.team}_{ctx.slot}",
"default": 0,
"want_reply": False,
"operations": [{"operation": "replace", "value": current_room}],
}
]
)
# Send locations if there are any to send.
if locs_to_send != self.local_checked_locations:
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)}])
except bizhawk.RequestFailedError:
# Exit handler and return to main loop to reconnect.
pass
except bizhawk.ConnectorError:
pass
def find_key(dictionary, target):
leftover = target
for key, value in dictionary.items():
if leftover > value:
leftover -= value
else:
return key, leftover
def id_to_RAM(id_: int):
code = id_
if 0x1C <= code <= 0x1F:
code += 0xE
if 0x20 <= code <= 0x26:
code -= 0x4
return code

5705
worlds/mlss/Data.py Normal file

File diff suppressed because it is too large Load Diff

190
worlds/mlss/Items.py Normal file
View File

@ -0,0 +1,190 @@
import typing
from BaseClasses import Item, ItemClassification
class ItemData(typing.NamedTuple):
code: int
itemName: str
classification: ItemClassification
itemID: int
class MLSSItem(Item):
game: str = "Mario & Luigi Superstar Saga"
itemList: typing.List[ItemData] = [
ItemData(77771000, "5 Coins", ItemClassification.filler, 0x4),
ItemData(77771001, "Mushroom", ItemClassification.filler, 0xA),
ItemData(77771002, "Super Mushroom", ItemClassification.filler, 0xB),
ItemData(77771003, "Ultra Mushroom", ItemClassification.filler, 0xC),
ItemData(77771004, "Max Mushroom", ItemClassification.filler, 0xD),
ItemData(77771005, "Nuts", ItemClassification.filler, 0xE),
ItemData(77771006, "Super Nuts", ItemClassification.filler, 0xF),
ItemData(77771007, "Ultra Nuts", ItemClassification.useful, 0x10),
ItemData(77771008, "Max Nuts", ItemClassification.useful, 0x11),
ItemData(77771009, "Syrup", ItemClassification.filler, 0x12),
ItemData(77771010, "Super Syrup", ItemClassification.filler, 0x13),
ItemData(77771011, "Ultra Syrup", ItemClassification.useful, 0x14),
ItemData(77771012, "Max Syrup", ItemClassification.useful, 0x15),
ItemData(77771013, "1-UP Mushroom", ItemClassification.useful, 0x16),
ItemData(77771014, "1-UP Super", ItemClassification.useful, 0x17),
ItemData(77771015, "Golden Mushroom", ItemClassification.useful, 0x18),
ItemData(77771016, "Refreshing Herb", ItemClassification.filler, 0x19),
ItemData(77771017, "Red Pepper", ItemClassification.useful, 0x1A),
ItemData(77771018, "Green Pepper", ItemClassification.useful, 0x1B),
ItemData(77771019, "Hoo Bean", ItemClassification.filler, 0x1D),
ItemData(77771020, "Chuckle Bean", ItemClassification.filler, 0x1E),
ItemData(77771021, "Woohoo Blend", ItemClassification.useful, 0x20),
ItemData(77771022, "Hoohoo Blend", ItemClassification.useful, 0x21),
ItemData(77771023, "Chuckle Blend", ItemClassification.useful, 0x22),
ItemData(77771024, "Teehee Blend", ItemClassification.useful, 0x23),
ItemData(77771025, "Hoolumbian", ItemClassification.useful, 0x24),
ItemData(77771026, "Chuckoccino", ItemClassification.useful, 0x25),
ItemData(77771027, "Teeheespresso", ItemClassification.useful, 0x26),
ItemData(77771028, "Peasley's Rose", ItemClassification.progression, 0x31),
ItemData(77771029, "Beanbean Brooch", ItemClassification.progression, 0x32),
ItemData(77771030, "Red Goblet", ItemClassification.progression, 0x33),
ItemData(77771031, "Green Goblet", ItemClassification.progression, 0x34),
ItemData(77771032, "Red Chuckola Fruit", ItemClassification.progression, 0x35),
ItemData(77771033, "White Chuckola Fruit", ItemClassification.progression, 0x36),
ItemData(77771034, "Purple Chuckola Fruit", ItemClassification.progression, 0x37),
ItemData(77771035, "Hammers", ItemClassification.progression, 0x38),
ItemData(77771036, "Firebrand", ItemClassification.progression, 0x39),
ItemData(77771037, "Thunderhand", ItemClassification.progression, 0x3A),
ItemData(77771038, "Membership Card", ItemClassification.progression, 0x40),
ItemData(77771039, "Winkle Card", ItemClassification.progression, 0x41),
ItemData(77771040, "Peach's Extra Dress", ItemClassification.progression, 0x42),
ItemData(77771041, "Fake Beanstar", ItemClassification.progression, 0x43),
ItemData(77771042, "Red Pearl Bean", ItemClassification.progression, 0x45),
ItemData(77771043, "Green Pearl Bean", ItemClassification.progression, 0x46),
ItemData(77771044, "Bean Fruit 1", ItemClassification.progression_skip_balancing, 0x47),
ItemData(77771045, "Bean Fruit 2", ItemClassification.progression_skip_balancing, 0x50),
ItemData(77771046, "Bean Fruit 3", ItemClassification.progression_skip_balancing, 0x51),
ItemData(77771047, "Bean Fruit 4", ItemClassification.progression_skip_balancing, 0x52),
ItemData(77771048, "Bean Fruit 5", ItemClassification.progression_skip_balancing, 0x53),
ItemData(77771049, "Bean Fruit 6", ItemClassification.progression_skip_balancing, 0x54),
ItemData(77771050, "Bean Fruit 7", ItemClassification.progression_skip_balancing, 0x55),
ItemData(77771051, "Blue Neon Egg", ItemClassification.progression, 0x56),
ItemData(77771052, "Red Neon Egg", ItemClassification.progression, 0x57),
ItemData(77771053, "Green Neon Egg", ItemClassification.progression, 0x60),
ItemData(77771054, "Yellow Neon Egg", ItemClassification.progression, 0x61),
ItemData(77771055, "Purple Neon Egg", ItemClassification.progression, 0x62),
ItemData(77771056, "Orange Neon Egg", ItemClassification.progression, 0x63),
ItemData(77771057, "Azure Neon Egg", ItemClassification.progression, 0x64),
ItemData(77771058, "Beanstar Piece 1", ItemClassification.progression, 0x65),
ItemData(77771059, "Beanstar Piece 2", ItemClassification.progression, 0x66),
ItemData(77771060, "Beanstar Piece 3", ItemClassification.progression, 0x67),
ItemData(77771061, "Beanstar Piece 4", ItemClassification.progression, 0x70),
ItemData(77771062, "Spangle", ItemClassification.progression, 0x72),
ItemData(77771063, "Beanlet 1", ItemClassification.filler, 0x73),
ItemData(77771064, "Beanlet 2", ItemClassification.filler, 0x74),
ItemData(77771065, "Beanlet 3", ItemClassification.filler, 0x75),
ItemData(77771066, "Beanlet 4", ItemClassification.filler, 0x76),
ItemData(77771067, "Beanlet 5", ItemClassification.filler, 0x77),
ItemData(77771068, "Beanstone 1", ItemClassification.filler, 0x80),
ItemData(77771069, "Beanstone 2", ItemClassification.filler, 0x81),
ItemData(77771070, "Beanstone 3", ItemClassification.filler, 0x82),
ItemData(77771071, "Beanstone 4", ItemClassification.filler, 0x83),
ItemData(77771072, "Beanstone 5", ItemClassification.filler, 0x84),
ItemData(77771073, "Beanstone 6", ItemClassification.filler, 0x85),
ItemData(77771074, "Beanstone 7", ItemClassification.filler, 0x86),
ItemData(77771075, "Beanstone 8", ItemClassification.filler, 0x87),
ItemData(77771076, "Beanstone 9", ItemClassification.filler, 0x90),
ItemData(77771077, "Beanstone 10", ItemClassification.filler, 0x91),
ItemData(77771078, "Secret Scroll 1", ItemClassification.useful, 0x92),
ItemData(77771079, "Secret Scroll 2", ItemClassification.useful, 0x93),
ItemData(77771080, "Castle Badge", ItemClassification.useful, 0x9F),
ItemData(77771081, "Pea Badge", ItemClassification.useful, 0xA0),
ItemData(77771082, "Bean B. Badge", ItemClassification.useful, 0xA1),
ItemData(77771083, "Counter Badge", ItemClassification.useful, 0xA2),
ItemData(77771084, "Charity Badge", ItemClassification.useful, 0xA3),
ItemData(77771085, "Bros. Badge", ItemClassification.useful, 0xA4),
ItemData(77771086, "Miracle Badge", ItemClassification.useful, 0xA5),
ItemData(77771087, "Ohoracle Badge", ItemClassification.useful, 0xA6),
ItemData(77771088, "Mush Badge", ItemClassification.useful, 0xA7),
ItemData(77771089, "Mari-Lui Badge", ItemClassification.useful, 0xA8),
ItemData(77771090, "Muscle Badge", ItemClassification.useful, 0xA9),
ItemData(77771091, "Spiny Badge AA", ItemClassification.useful, 0xAA),
ItemData(77771092, "Mush Badge A", ItemClassification.useful, 0xAB),
ItemData(77771093, "Grab Badge", ItemClassification.useful, 0xAC),
ItemData(77771094, "Mush Badge AA", ItemClassification.useful, 0xAD),
ItemData(77771095, "Power Badge", ItemClassification.useful, 0xAE),
ItemData(77771096, "Wonder Badge", ItemClassification.useful, 0xAF),
ItemData(77771097, "Beauty Badge", ItemClassification.useful, 0xB0),
ItemData(77771098, "Salvage Badge", ItemClassification.useful, 0xB1),
ItemData(77771099, "Oh-Pah Badge", ItemClassification.useful, 0xB2),
ItemData(77771100, "Brilliant Badge", ItemClassification.useful, 0xB3),
ItemData(77771101, "Sarge Badge", ItemClassification.useful, 0xB4),
ItemData(77771102, "General Badge", ItemClassification.useful, 0xB5),
ItemData(77771103, "Tank Badge", ItemClassification.useful, 0xB6),
ItemData(77771104, "Bros. Rock", ItemClassification.useful, 0xBD),
ItemData(77771105, "Soulful Bros.", ItemClassification.useful, 0xC0),
ItemData(77771106, "High-End Badge", ItemClassification.useful, 0xC1),
ItemData(77771107, "Bean Pants", ItemClassification.useful, 0xCC),
ItemData(77771108, "Bean Trousers", ItemClassification.useful, 0xCD),
ItemData(77771109, "Blue Jeans", ItemClassification.useful, 0xCE),
ItemData(77771110, "Parasol Pants", ItemClassification.useful, 0xCF),
ItemData(77771111, "Hard Pants", ItemClassification.useful, 0xD0),
ItemData(77771112, "Heart Jeans", ItemClassification.useful, 0xD1),
ItemData(77771113, "Plaid Trousers", ItemClassification.useful, 0xD2),
ItemData(77771114, "#1 Trousers", ItemClassification.useful, 0xD3),
ItemData(77771115, "Safety Slacks", ItemClassification.useful, 0xD4),
ItemData(77771116, "Shroom Pants", ItemClassification.useful, 0xD5),
ItemData(77771117, "Shroom Bells", ItemClassification.useful, 0xD6),
ItemData(77771118, "Shroom Slacks", ItemClassification.useful, 0xD7),
ItemData(77771119, "Peachy Jeans", ItemClassification.useful, 0xD8),
ItemData(77771120, "Mushwin Pants", ItemClassification.useful, 0xD9),
ItemData(77771121, "Mushluck Pants", ItemClassification.useful, 0xDA),
ItemData(77771122, "Scandal Jeans", ItemClassification.useful, 0xDB),
ItemData(77771123, "Street Jeans", ItemClassification.useful, 0xDC),
ItemData(77771124, "Tropic Slacks", ItemClassification.useful, 0xDD),
ItemData(77771125, "Hermetic Pants", ItemClassification.useful, 0xDE),
ItemData(77771126, "Beanstar Pants", ItemClassification.useful, 0xDF),
ItemData(77771127, "Peasley Slacks", ItemClassification.useful, 0xE0),
ItemData(77771128, "Queen B. Jeans", ItemClassification.useful, 0xE1),
ItemData(77771129, "B. Brand Jeans", ItemClassification.useful, 0xE2),
ItemData(77771130, "Heart Slacks", ItemClassification.useful, 0xE3),
ItemData(77771131, "Casual Slacks", ItemClassification.useful, 0xE4),
ItemData(77771132, "Casual Coral", ItemClassification.useful, 0xEB),
ItemData(77771133, "Harhall's Pants", ItemClassification.useful, 0xF1),
ItemData(77771134, "Wool Trousers", ItemClassification.useful, 0xF3),
ItemData(77771135, "Iron Pants", ItemClassification.useful, 0xF7),
ItemData(77771136, "Greed Wallet", ItemClassification.useful, 0xF8),
ItemData(77771137, "Bonus Ring", ItemClassification.useful, 0xF9),
ItemData(77771138, "Excite Spring", ItemClassification.useful, 0xFA),
ItemData(77771139, "Great Force", ItemClassification.useful, 0xFB),
ItemData(77771140, "Power Grip", ItemClassification.useful, 0xFC),
ItemData(77771141, "Cobalt Necktie", ItemClassification.useful, 0xFD),
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),
]
item_frequencies: typing.Dict[str, int] = {
"5 Coins": 40,
"Mushroom": 55,
"Super Mushroom": 15,
"Ultra Mushroom": 12,
"Nuts": 10,
"Super Nuts": 5,
"Ultra Nuts": 5,
"Max Nuts": 2,
"Syrup": 28,
"Super Syrup": 10,
"Ultra Syrup": 10,
"Max Syrup": 2,
"1-Up Mushroom": 15,
"1-Up Super": 5,
"Golden Mushroom": 3,
"Refreshing Herb": 9,
"Red Pepper": 2,
"Green Pepper": 2,
"Hoo Bean": 100,
"Chuckle Bean": 200,
"Hammers": 3,
}
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}

1185
worlds/mlss/Locations.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,559 @@
class LocationName:
StardustFields1Block1 = "Stardust Fields Room 1 Block 1"
StardustFields1Block2 = "Stardust Fields Room 1 Block 2"
StardustFields2Block = "Stardust Fields Room 2 Block"
StardustFields3Block = "Stardust Fields Room 3 Block"
StardustFields4Block1 = "Stardust Fields Room 4 Block 1"
StardustFields4Block2 = "Stardust Fields Room 4 Block 2"
StardustFields4Block3 = "Stardust Fields Room 4 Block 3"
StardustFields5Block = "Stardust Fields Room 5 Block"
HoohooVillageHammerHouseBlock = "Hoohoo Village Hammer House Block"
BeanbeanCastleTownLeftSideHouseBlock1 = "Beanbean Castle Town Left Side House Block 1"
BeanbeanCastleTownLeftSideHouseBlock2 = "Beanbean Castle Town Left Side House Block 2"
BeanbeanCastleTownLeftSideHouseBlock3 = "Beanbean Castle Town Left Side House Block 3"
BeanbeanCastleTownLeftSideHouseBlock4 = "Beanbean Castle Town Left Side House Block 4"
BeanbeanCastleTownRightSideHouseBlock1 = "Beanbean Castle Town Right Side House Block 1"
BeanbeanCastleTownRightSideHouseBlock2 = "Beanbean Castle Town Right Side House Block 2"
BeanbeanCastleTownRightSideHouseBlock3 = "Beanbean Castle Town Right Side House Block 3"
BeanbeanCastleTownRightSideHouseBlock4 = "Beanbean Castle Town Right Side House Block 4"
BeanbeanCastleTownMiniMarioBlock1 = "Beanbean Castle Town Mini Mario Block 1"
BeanbeanCastleTownMiniMarioBlock2 = "Beanbean Castle Town Mini Mario Block 2"
BeanbeanCastleTownMiniMarioBlock3 = "Beanbean Castle Town Mini Mario Block 3"
BeanbeanCastleTownMiniMarioBlock4 = "Beanbean Castle Town Mini Mario Block 4"
BeanbeanCastleTownMiniMarioBlock5 = "Beanbean Castle Town Mini Mario Block 5"
HoohooMountainSummitDigspot = "Hoohoo Mountain Summit Digspot"
HoohooMountainBelowSummitDigspot = "Hoohoo Mountain Below Summit Digspot"
HoohooMountainBelowSummitBlock1 = "Hoohoo Mountain Below Summit Block 1"
HoohooMountainBelowSummitBlock2 = "Hoohoo Mountain Below Summit Block 2"
HoohooMountainBelowSummitBlock3 = "Hoohoo Mountain Below Summit Block 3"
HoohooMountainAfterHoohoorosBlock1 = "Hoohoo Mountain After Hoohooros Block 1"
HoohooMountainAfterHoohoorosDigspot = "Hoohoo Mountain After Hoohooros Digspot"
HoohooMountainAfterHoohoorosBlock2 = "Hoohoo Mountain After Hoohooros Block 2"
HoohooMountainHoohoorosRoomBlock1 = "Hoohoo Mountain Hoohooros Room Block 1"
HoohooMountainHoohoorosRoomBlock2 = "Hoohoo Mountain Hoohooros Room Block 2"
HoohooMountainHoohoorosRoomDigspot1 = "Hoohoo Mountain Hoohooros Room Digspot 1"
HoohooMountainHoohoorosRoomDigspot2 = "Hoohoo Mountain Hoohooros Room Digspot 2"
HoohooMountainBeforeHoohoorosBlock = "Hoohoo Mountain Before Hoohooros Block"
HoohooMountainBeforeHoohoorosDigspot = "Hoohoo Mountain Before Hoohooros Digspot"
HoohooMountainFountainRoomBlock1 = "Hoohoo Mountain Fountain Room Block 1"
HoohooMountainFountainRoomBlock2 = "Hoohoo Mountain Fountain Room Block 2"
HoohooMountainRoom2Digspot1 = "Hoohoo Mountain Room 2 Digspot 1"
HoohooMountainRoom2Digspot2 = "Hoohoo Mountain Room 2 Digspot 2"
HoohooMountainRoom1Block1 = "Hoohoo Mountain Room 1 Block 1"
HoohooMountainRoom1Block2 = "Hoohoo Mountain Room 1 Block 2"
HoohooMountainRoom1Block3 = "Hoohoo Mountain Room 1 Block 3"
HoohooMountainBaseRoom1Block = "Hoohoo Mountain Base Room 1 Block"
HoohooMountainBaseRoom1Digspot = "Hoohoo Mountain Base Room 1 Digspot"
HoohooVillageRightSideBlock = "Hoohoo Village Right Side Block"
HoohooVillageRightSideDigspot = "Hoohoo Village Right Side Digspot"
HoohooVillageBridgeRoomBlock1 = "Hoohoo Village Bridge Room Block 1"
HoohooVillageBridgeRoomBlock2 = "Hoohoo Village Bridge Room Block 2"
HoohooVillageBridgeRoomBlock3 = "Hoohoo Village Bridge Room Block 3"
HoohooMountainBaseBridgeRoomBlock1 = "Hoohoo Mountain Base Bridge Room Block 1"
HoohooMountainBaseBridgeRoomBlock2 = "Hoohoo Mountain Base Bridge Room Block 2"
HoohooMountainBaseBridgeRoomBlock3 = "Hoohoo Mountain Base Bridge Room Block 3"
HoohooMountainBaseBridgeRoomBlock4 = "Hoohoo Mountain Base Bridge Room Block 4"
HoohooMountainBaseBridgeRoomDigspot = "Hoohoo Mountain Base Bridge Room Digspot"
HoohooMountainBaseBoostatueRoomBlock1 = "Hoohoo Mountain Base Boostatue Room Block 1"
HoohooMountainBaseBoostatueRoomBlock2 = "Hoohoo Mountain Base Boostatue Room Block 2"
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"
HoohooMountainBaseGrassyAreaBlock1 = "Hoohoo Mountain Base Grassy Area Block 1"
HoohooMountainBaseGrassyAreaBlock2 = "Hoohoo Mountain Base Grassy Area Block 2"
HoohooMountainBaseGuffawhaRuinsEntranceDigspot = "Hoohoo Mountain Base Guffawha Ruins Entrance Digspot"
HoohooMountainBaseTeeheeValleyEntranceDigspot = "Hoohoo Mountain Base Teehee Valley Entrance Digspot"
HoohooMountainBaseTeeheeValleyEntranceBlock = "Hoohoo Mountain Base Teehee Valley Entrance Block"
HoohooMountainBaseAfterMinecartMinigameBlock1 = "Hoohoo Mountain Base After Minecart Minigame Block 1"
HoohooMountainBaseAfterMinecartMinigameBlock2 = "Hoohoo Mountain Base After Minecart Minigame Block 2"
HoohooMountainBasePastUltraHammerRocksBlock1 = "Hoohoo Mountain Base Past Ultra Hammer Rocks Block 1"
HoohooMountainBasePastUltraHammerRocksBlock2 = "Hoohoo Mountain Base Past Ultra Hammer Rocks Block 2"
HoohooMountainBasePastUltraHammerRocksBlock3 = "Hoohoo Mountain Base Past Ultra Hammer Rocks Block 3"
CaveConnectingStardustFieldsAndHoohooVillageBlock1 = "Cave Connecting Stardust Fields and Hoohoo Village Block 1"
CaveConnectingStardustFieldsAndHoohooVillageBlock2 = "Cave Connecting Stardust Fields and Hoohoo Village Block 2"
HoohooVillageSouthCaveBlock = "Hoohoo Village South Cave Block"
HoohooVillageSuperHammerCaveDigspot = "Hoohoo Village Super Hammer Cave Digspot"
HoohooVillageSuperHammerCaveBlock = "Hoohoo Village Super Hammer Cave Block"
HoohooVillageNorthCaveRoom1Block = "Hoohoo Village North Cave Room 1 Block"
HoohooVillageNorthCaveRoom2Block = "Hoohoo Village North Cave Room 2 Block"
HoohooVillageNorthCaveRoom2Digspot = "Hoohoo Village North Cave Room 2 Digspot"
HoohooMountainBaseMinecartCaveDigspot = "Hoohoo Mountain Base Minecart Cave Digspot"
BeanbeanOutskirtsFarmRoomDigspot1 = "Beanbean Outskirts Farm Room Digspot 1"
BeanbeanOutskirtsFarmRoomDigspot2 = "Beanbean Outskirts Farm Room Digspot 2"
BeanbeanOutskirtsFarmRoomDigspot3 = "Beanbean Outskirts Farm Room Digspot 3"
BeanbeanOutskirtsNWBlock = "Beanbean Outskirts NW Block"
BeanbeanOutskirtsNWDigspot = "Beanbean Outskirts NW Digspot"
BeanbeanOutskirtsWDigspot1 = "Beanbean Outskirts W Digspot 1"
BeanbeanOutskirtsWDigspot2 = "Beanbean Outskirts W"
BeanbeanOutskirtsNRoom1Digspot = "Beanbean Outskirts N Room 1 Digspot"
BeanbeanOutskirtsNRoom2Digspot = "Beanbean Outskirts N Room 2 Digspot"
BeanbeanOutskirtsSRoom1Digspot1 = "Beanbean Outskirts S Room 1 Digspot 1"
BeanbeanOutskirtsSRoom1Block = "Beanbean Outskirts S Room 1 Block"
BeanbeanOutskirtsSRoom1Digspot2 = "Beanbean Outskirts S Room 1 Digspot 2"
BeanbeanOutskirtsSRoom2Block1 = "Beanbean Outskirts S Room 2 Block 1"
BeanbeanOutskirtsSRoom2Digspot1 = "Beanbean Outskirts S Room 2 Digspot 1"
BeanbeanOutskirtsSRoom2Digspot2 = "Beanbean Outskirts S Room 2 Digspot 2"
BeanbeanOutskirtsSRoom2Block2 = "Beanbean Outskirts S Room 2 Block 2"
BeanbeanOutskirtsSRoom2Digspot3 = "Beanbean Outskirts S Room 2 Digspot 3"
BeanbeanOutskirtsNEDigspot1 = "Beanbean Outskirts NE Digspot 1"
BeanbeanOutskirtsNEDigspot2 = "Beanbean Outskirts NE Digspot 2"
BeanbeanOutskirtsEDigspot1 = "Beanbean Outskirts E Digspot 1"
BeanbeanOutskirtsEDigspot2 = "Beanbean Outskirts E Digspot 2"
BeanbeanOutskirtsEDigspot3 = "Beanbean Outskirts E Digspot 3"
BeanbeanOutskirtsSEDigspot1 = "Beanbean Outskirts SE Digspot 1"
BeanbeanOutskirtsSEDigspot2 = "Beanbean Outskirts SE Digspot 2"
BeanbeanOutskirtsSEDigspot3 = "Beanbean Outskirts SE Digspot 3"
BeanbeanOutskirtsNorthBeachDigspot1 = "Beanbean Outskirts North Beach Digspot 1"
BeanbeanOutskirtsNorthBeachDigspot2 = "Beanbean Outskirts North Beach Digspot 2"
BeanbeanOutskirtsNorthBeachDigspot3 = "Beanbean Outskirts North Beach Digspot 3"
BeanbeanOutskirtsSouthBeachDigspot = "Beanbean Outskirts South Beach Digspot"
BeanbeanOutskirtsSurfBeachDigspot1 = "Beanbean Outskirts Surf Beach Digspot 1"
BeanbeanOutskirtsSurfBeachBlock = "Beanbean Outskirts Surf Beach Block"
BeanbeanOutskirtsSurfBeachDigspot2 = "Beanbean Outskirts Surf Beach Digspot 2"
BeanbeanOutskirtsSurfBeachDigspot3 = "Beanbean Outskirts Surf Beach Digspot 3"
ChateauRoom1Digspot = "Chateau Room 1 Digspot"
ChateauPoppleFightRoomBlock1 = "Chateau Popple Fight Room Block 1"
ChateauPoppleFightRoomBlock2 = "Chateau Popple Fight Room Block 2"
ChateauPoppleFightRoomDigspot = "Chateau Popple Fight Room Digspot"
ChateauBarrelRoomDigspot = "Chateau Barrel Room Digspot"
ChateauGobletRoomDigspot = "Chateau Goblet Room Digspot"
ChucklehuckWoodsCaveRoom1Block1 = "Chucklehuck Woods Cave Room 1 Block 1"
ChucklehuckWoodsCaveRoom1Block2 = "Chucklehuck Woods Cave Room 1 Block 2"
ChucklehuckWoodsCaveRoom2Block = "Chucklehuck Woods Cave Room 2 Block"
ChucklehuckWoodsCaveRoom3Block = "Chucklehuck Woods Cave Room 3 Block"
ChucklehuckWoodsRoom2Block = "Chucklehuck Woods Room 2 Block"
ChucklehuckWoodsRoom2Digspot = "Chucklehuck Woods Room 2 Digspot"
ChucklehuckWoodsPipeRoomBlock1 = "Chucklehuck Woods Pipe Room Block 1"
ChucklehuckWoodsPipeRoomBlock2 = "Chucklehuck Woods Pipe Room Block 2"
ChucklehuckWoodsPipeRoomDigspot1 = "Chucklehuck Woods Pipe Room Digspot 1"
ChucklehuckWoodsPipeRoomDigspot2 = "Chucklehuck Woods Pipe Room Digspot 2"
ChucklehuckWoodsRoom4Block1 = "Chucklehuck Woods Room 4 Block 1"
ChucklehuckWoodsRoom4Block2 = "Chucklehuck Woods Room 4 Block 2"
ChucklehuckWoodsRoom4Block3 = "Chucklehuck Woods Room 4 Block 3"
ChucklehuckWoodsRoom7Block1 = "Chucklehuck Woods Room 7 Block 1"
ChucklehuckWoodsRoom7Block2 = "Chucklehuck Woods Room 7 Block 2"
ChucklehuckWoodsRoom7Digspot1 = "Chucklehuck Woods Room 7 Digspot 1"
ChucklehuckWoodsRoom7Digspot2 = "Chucklehuck Woods Room 7 Digspot 2"
ChucklehuckWoodsRoom8Digspot = "Chucklehuck Woods Room 8 Digspot"
ChucklehuckWoodsEastOfChucklerootDigspot = "Chucklehuck Woods East of Chuckleroot Digspot"
ChucklehuckWoodsNortheastOfChucklerootDigspot1 = "Chucklehuck Woods Northeast of Chuckleroot Digspot 1"
ChucklehuckWoodsNortheastOfChucklerootDigspot2 = "Chucklehuck Woods Northeast of Chuckleroot Digspot 2"
ChucklehuckWoodsNortheastOfChucklerootDigspot3 = "Chucklehuck Woods Northeast of Chuckleroot Digspot 3"
ChucklehuckWoodsNortheastOfChucklerootDigspot4 = "Chucklehuck Woods Northeast of Chuckleroot Digspot 4"
ChucklehuckWoodsWhiteFruitRoomDigspot1 = "Chucklehuck Woods White Fruit Room Digspot 1"
ChucklehuckWoodsWhiteFruitRoomDigspot2 = "Chucklehuck Woods White Fruit Room Digspot 2"
ChucklehuckWoodsWhiteFruitRoomDigspot3 = "Chucklehuck Woods White Fruit Room Digspot 3"
ChucklehuckWoodsWestOfChucklerootBlock = "Chucklehuck Woods West of Chuckleroot Block"
ChucklehuckWoodsSouthwestOfChucklerootBlock = "Chucklehuck Woods Southwest of Chuckleroot Block"
ChucklehuckWoodsWigglerRoomDigspot1 = "Chucklehuck Woods Wiggler Room Digspot 1"
ChucklehuckWoodsWigglerRoomDigspot2 = "Chucklehuck Woods Wiggler Room Digspot 2"
ChucklehuckWoodsAfterChucklerootBlock1 = "Chucklehuck Woods After Chuckleroot Block 1"
ChucklehuckWoodsAfterChucklerootBlock2 = "Chucklehuck Woods After Chuckleroot Block 2"
ChucklehuckWoodsAfterChucklerootBlock3 = "Chucklehuck Woods After Chuckleroot Block 3"
ChucklehuckWoodsAfterChucklerootBlock4 = "Chucklehuck Woods After Chuckleroot Block 4"
ChucklehuckWoodsAfterChucklerootBlock5 = "Chucklehuck Woods After Chuckleroot Block 5"
ChucklehuckWoodsAfterChucklerootBlock6 = "Chucklehuck Woods After Chuckleroot Block 6"
WinkleAreaBeanstarRoomBlock = "Winkle Area Beanstar Room Block"
WinkleAreaDigspot = "Winkle Area Digspot"
WinkleAreaOutsideColosseumBlock = "Winkle Area Outside Colosseum Block"
ChucklehuckWoodsKoopaRoomBlock1 = "Chucklehuck Woods Koopa Room Block 1"
ChucklehuckWoodsKoopaRoomBlock2 = "Chucklehuck Woods Koopa Room Block 2"
ChucklehuckWoodsKoopaRoomDigspot = "Chucklehuck Woods Koopa Room Digspot"
ChucklehuckWoodsWinkleCaveBlock1 = "Chucklehuck Woods Winkle Cave Block 1"
ChucklehuckWoodsWinkleCaveBlock2 = "Chucklehuck Woods Winkle Cave Block 2"
OhoOasisWestDigspot = "Oho Oasis West Digspot"
OhoOasisFirePalaceBlock = "Oho Oasis Fire Palace Block"
SewersRoom3Block1 = "Sewers Room 3 Block 1"
SewersRoom3Block2 = "Sewers Room 3 Block 2"
SewersRoom3Block3 = "Sewers Room 3 Block 3"
SewersRoom5Block1 = "Sewers Room 5 Block 1"
SewersRoom5Block2 = "Sewers Room 5 Block 2"
SewersPrisonRoomBlock1 = "Sewers Prison Room Block 1"
SewersPrisonRoomBlock2 = "Sewers Prison Room Block 2"
SewersPrisonRoomBlock3 = "Sewers Prison Room Block 3"
SewersPrisonRoomBlock4 = "Sewers Prison Room Block 4"
OhoOceanFirePuzzleRoomDigspot = "Oho Ocean Fire Puzzle Room Digspot"
OhoOceanSouthRoom1Block = "Oho Ocean South Room 1 Block"
OhoOceanSouthRoom2Digspot = "Oho Ocean South Room 2 Digspot"
OhoOceanSpikeRoomDigspot1 = "Oho Ocean Spike Room Digspot 1"
OhoOceanSpikeRoomDigspot2 = "Oho Ocean Spike Room Digspot 2"
OceanNorthWhirlpoolBlock1 = "Oho Ocean North Whirlpool Block 1"
OceanNorthWhirlpoolBlock2 = "Oho Ocean North Whirlpool Block 2"
OceanNorthWhirlpoolBlock3 = "Oho Ocean North Whirlpool Block 3"
OceanNorthWhirlpoolBlock4 = "Oho Ocean North Whirlpool Block 4"
OceanNorthWhirlpoolDigspot1 = "Oho Ocean North Whirlpool Digspot 1"
OceanNorthWhirlpoolDigspot2 = "Oho Ocean North Whirlpool Digspot 2"
OceanSouthWhirlpoolDigspot1 = "Oho Ocean South Whirlpool Digspot 1"
OceanSouthWhirlpoolDigspot2 = "Oho Ocean South Whirlpool Digspot 2"
OceanSouthWhirlpoolDigspot3 = "Oho Ocean South Whirlpool Digspot 3"
OceanSouthWhirlpoolDigspot4 = "Oho Ocean South Whirlpool Digspot 4"
OceanSouthWhirlpoolDigspot5 = "Oho Ocean South Whirlpool Digspot 5"
OceanSouthWhirlpoolDigspot6 = "Oho Ocean South Whirlpool Digspot 6"
OceanSouthWhirlpoolRoom2Digspot = "Oho Ocean South Whirlpool Room 2 Digspot"
WoohooHooniversityStarRoomBlock1 = "Woohoo Hooniversity Star Room Block 1"
WoohooHooniversityStarRoomBlock2 = "Woohoo Hooniversity Star Room Block 2"
WoohooHooniversityStarRoomBlock3 = "Woohoo Hooniversity Star Room Block 3"
WoohooHooniversitySunDoorBlock1 = "Woohoo Hooniversity Sun Door Block 1"
WoohooHooniversitySunDoorBlock2 = "Woohoo Hooniversity Sun Door Block 2"
WoohooHooniversitySouthOfStarRoomBlock = "Woohoo Hooniversity South Of Star Room Block"
WoohooHooniversityWestOfStarRoomDigspot1 = "Woohoo Hooniversity West Of Star Room Digspot 1"
WoohooHooniversityWestOfStarRoomDigspot2 = "Woohoo Hooniversity West Of Star Room Digspot 2"
WoohooHooniversityBarrelPuzzleEntranceDigspot1 = "Woohoo Hooniversity Barrel Puzzle Entrance Digspot 1"
WoohooHooniversityBarrelPuzzleEntranceBlock1 = "Woohoo Hooniversity Barrel Puzzle Entrance Block 1"
WoohooHooniversityBarrelPuzzleEntranceBlock2 = "Woohoo Hooniversity Barrel Puzzle Entrance Block 2"
WoohooHooniversityBarrelPuzzleEntranceBlock3 = "Woohoo Hooniversity Barrel Puzzle Entrance Block 3"
WoohooHooniversityBarrelPuzzleEntranceBlock4 = "Woohoo Hooniversity Barrel Puzzle Entrance Block 4"
WoohooHooniversityBarrelPuzzleEntranceDigspot2 = "Woohoo Hooniversity Barrel Puzzle Entrance Digspot 2"
ChucklehuckWoodsRoom1Digspot = "Chucklehuck Woods Room 1 Digspot"
WoohooHooniversityWestOfStarRoom2Digspot = "Woohoo Hooniversity West of Star Room 2 Digspot"
WoohooHooniversityWestOfStarRoom3Digspot = "Woohoo Hooniversity West of Star Room 3 Digspot"
WoohooHooniversityWestOfStarRoom4Block1 = "Woohoo Hooniversity West of Star Room 4 Block 1"
WoohooHooniversityWestOfStarRoom4Block2 = "Woohoo Hooniversity West of Star Room 4 Block 2"
WoohooHooniversityWestOfStarRoom4Block3 = "Woohoo Hooniversity West of Star Room 4 Block 3"
WoohooHooniversityWestOfStarRoom4Digspot1 = "Woohoo Hooniversity West of Star Room 4 Digspot 1"
WoohooHooniversityWestOfStarRoom4Digspot2 = "Woohoo Hooniversity West of Star Room 4 Digspot 2"
WoohooHooniversityWestOfStarRoom5Digspot = "Woohoo Hooniversity West of Star Room 5 Digspot"
WoohooHooniversityEntranceToMiniMarioRoomDigspot1 = "Woohoo Hooniversity Entrance to Mini Mario Room Digspot 1"
WoohooHooniversityEntranceToMiniMarioRoomDigspot2 = "Woohoo Hooniversity Entrance to Mini Mario Room Digspot 2"
WoohooHooniversityEntranceToMiniMarioRoom2Digspot = "Woohoo Hooniversity Entrance to Mini Mario Room 2 Digspot"
WoohooHooniversityMiniMarioPuzzleBlock = "Woohoo Hooniversity Mini Mario Puzzle Block"
WoohooHooniversityMiniMarioPuzzleDigspot = "Woohoo Hooniversity Mini Mario Puzzle Digspot"
WoohooHooniversityMiniMarioPuzzleSecretAreaBlock1 = "Woohoo Hooniversity Mini Mario Puzzle Secret Area Block 1"
WoohooHooniversityMiniMarioPuzzleSecretAreaBlock2 = "Woohoo Hooniversity Mini Mario Puzzle Secret Area Block 2"
WoohooHooniversityMiniMarioPuzzleSecretAreaBlock3 = "Woohoo Hooniversity Mini Mario Puzzle Secret Area Block 3"
WoohooHooniversityMiniMarioPuzzleSecretAreaBlock4 = "Woohoo Hooniversity Mini Mario Puzzle Secret Area Block 4"
WoohooHooniversityPastSunDoorBlock1 = "Woohoo Hooniversity Past Sun Door Block 1"
WoohooHooniversityPastSunDoorBlock2 = "Woohoo Hooniversity Past Sun Door Block 2"
WoohooHooniversityPastSunDoorBlock3 = "Woohoo Hooniversity Past Sun Door Block 3"
WoohooHooniversityPastCacklettaRoom1Block = "Woohoo Hooniversity Past Cackletta Room 1 Block"
WoohooHooniversityPastCacklettaRoom2Block1 = "Woohoo Hooniversity Past Cackletta Room 2 Block 1"
WoohooHooniversityPastCacklettaRoom2Block2 = "Woohoo Hooniversity Past Cackletta Room 2 Block 2"
WoohooHooniversityPastCacklettaRoom2Digspot = "Woohoo Hooniversity Past Cackletta Room 2 Digspot"
AirportEntranceDigspot = "Airport Entrance Digspot"
AirportLobbyDigspot = "Airport Lobby Digspot"
AirportLeftsideDigspot1 = "Airport Leftside Digspot 1"
AirportLeftsideDigspot2 = "Airport Leftside Digspot 2"
AirportLeftsideDigspot3 = "Airport Leftside Digspot 3"
AirportLeftsideDigspot4 = "Airport Leftside Digspot 4"
AirportLeftsideDigspot5 = "Airport Leftside Digspot 5"
AirportCenterDigspot1 = "Airport Center Digspot 1"
AirportCenterDigspot2 = "Airport Center Digspot 2"
AirportCenterDigspot3 = "Airport Center Digspot 3"
AirportCenterDigspot4 = "Airport Center Digspot 4"
AirportCenterDigspot5 = "Airport Center Digspot 5"
AirportRightsideDigspot1 = "Airport Rightside Digspot 1"
AirportRightsideDigspot2 = "Airport Rightside Digspot 2"
AirportRightsideDigspot3 = "Airport Rightside Digspot 3"
AirportRightsideDigspot4 = "Airport Rightside Digspot 4"
AirportRightsideDigspot5 = "Airport Rightside Digspot 5"
GwarharLagoonPipeRoomDigspot = "Gwarhar Lagoon Pipe Room Digspot"
GwarharLagoonMassageParlorEntranceDigspot = "Gwarhar Lagoon Massage Parlor Entrance Digspot"
GwarharLagoonPastHermieDigspot = "Gwarhar Lagoon Past Hermie Digspot"
GwarharLagoonEntranceToWestUnderwaterAreaDigspot = "Gwarhar Lagoon Entrance to West Underwater Area Digspot"
GwarharLagoonFireDashPuzzleRoom1Digspot1 = "Gwarhar Lagoon Fire Dash Puzzle Room 1 Digspot 1"
GwarharLagoonFireDashPuzzleRoom1Digspot2 = "Gwarhar Lagoon Fire Dash Puzzle Room 1 Digspot 2"
GwarharLagoonFireDashPuzzleRoom2Digspot = "Gwarhar Lagoon Fire Dash Puzzle Room 2 Digspot"
GwarharLagoonFireDashPuzzleRoom3Digspot1 = "Gwarhar Lagoon Fire Dash Puzzle Room 3 Digspot 1"
GwarharLagoonFireDashPuzzleRoom3Digspot2 = "Gwarhar Lagoon Fire Dash Puzzle Room 3 Digspot 2"
GwarharLagoonEastOfStoneBridgeBlock = "Gwarhar Lagoon East of Stone Bridge Block"
GwarharLagoonNorthOfSpangleRoomDigspot = "Gwarhar Lagoon North of Spangle Room Digspot"
GwarharLagoonWestOfSpangleRoomDigspot = "Gwarhar Lagoon West of Spangle Room Digspot"
GwarharLagoonSpangleRoomBlock = "Gwarhar Lagoon Spangle Room Block"
GwarharLagoonFirstUnderwaterAreaRoom1Block = "Gwarhar Lagoon First Underwater Area Room 1 Block"
GwarharLagoonFirstUnderwaterAreaRoom2Block1 = "Gwarhar Lagoon First Underwater Area Room 2 Block 1"
GwarharLagoonFirstUnderwaterAreaRoom2Block2 = "Gwarhar Lagoon First Underwater Area Room 2 Block 2"
GwarharLagoonSecondUnderwaterAreaRoom4Digspot = "Gwarhar Lagoon Second Underwater Area Room 4 Digspot"
GwarharLagoonSecondUnderwaterAreaRoom2Digspot1 = "Gwarhar Lagoon Second Underwater Area Room 2 Digspot 1"
GwarharLagoonSecondUnderwaterAreaRoom2Digspot2 = "Gwarhar Lagoon Second Underwater Area Room 2 Digspot 2"
GwarharLagoonSecondUnderwaterAreaRoom3Block1 = "Gwarhar Lagoon Second Underwater Area Room 3 Block 1"
GwarharLagoonSecondUnderwaterAreaRoom3Block2 = "Gwarhar Lagoon Second Underwater Area Room 3 Block 2"
GwarharLagoonSecondUnderwaterAreaRoom3Block3 = "Gwarhar Lagoon Second Underwater Area Room 3 Block 3"
GwarharLagoonSecondUnderwaterAreaRoom1Digspot = "Gwarhar Lagoon Second Underwater Area Room 1 Digspot"
WoohooHooniversityBasementRoom1Digspot = "Woohoo Hooniversity Basement Room 1 Digspot"
WoohooHooniversityBasementRoom2Digspot = "Woohoo Hooniversity Basement Room 2 Digspot"
WoohooHooniversityBasementRoom3Block = "Woohoo Hooniversity Basement Room 3 Block"
WoohooHooniversityBasementRoom4Block = "Woohoo Hooniversity Basement Room 4 Block"
WoohooHooniversityPoppleRoomDigspot1 = "Woohoo Hooniversity Popple Room Digspot 1"
WoohooHooniversityPoppleRoomDigspot2 = "Woohoo Hooniversity Popple Room Digspot 2"
TeeheeValleyBeforePoppleDigspot1 = "Teehee Valley Before Popple Digspot 1"
TeeheeValleyBeforePoppleDigspot2 = "Teehee Valley Before Popple Digspot 2"
TeeheeValleyBeforePoppleDigspot3 = "Teehee Valley Before Popple Digspot 3"
TeeheeValleyBeforePoppleDigspot4 = "Teehee Valley Before Popple Digspot 4"
TeeheeValleyRoom1Digspot1 = "Teehee Valley Room 1 Digspot 1"
TeeheeValleyRoom1Digspot2 = "Teehee Valley Room 1 Digspot 2"
TeeheeValleyRoom1Digspot3 = "Teehee Valley Room 1 Digspot 3"
TeeheeValleyEastRoomDigspot1 = "Teehee Valley East Room Digspot 1"
TeeheeValleyEastRoomDigspot2 = "Teehee Valley East Room Digspot 2"
TeeheeValleyEastRoomDigspot3 = "Teehee Valley East Room Digspot 3"
TeeheeValleySoloMarioRoomDigspot1 = "Teehee Valley Solo Mario Room Digspot 1"
TeeheeValleySoloMarioRoomDigspot2 = "Teehee Valley Solo Mario Room Digspot 2"
TeeheeValleySoloMarioRoomDigspot3 = "Teehee Valley Solo Mario Room Digspot 3"
TeeheeValleySoloMarioRoomDigspot4 = "Teehee Valley Solo Mario Room Digspot 4"
TeeheeValleyPastUltraHammersBlock1 = "Teehee Valley Past Ultra Hammer Rock Block 1"
TeeheeValleyPastUltraHammersBlock2 = "Teehee Valley Past Ultra Hammer Rock Block 2"
TeeheeValleyPastUltraHammersDigspot1 = "Teehee Valley Past Ultra Hammer Rock Digspot 1"
TeeheeValleyPastUltraHammersDigspot2 = "Teehee Valley Past Ultra Hammer Rock Digspot 2 (Post-Birdo)"
TeeheeValleyPastUltraHammersDigspot3 = "Teehee Valley Past Ultra Hammer Rock Digspot 3"
TeeheeValleyEntranceToHoohooMountainDigspot = "Teehee Valley Entrance To Hoohoo Mountain Digspot"
TeeheeValleySoloLuigiMazeRoom2Digspot1 = "Teehee Valley Solo Luigi Maze Room 2 Digspot 1"
TeeheeValleySoloLuigiMazeRoom2Digspot2 = "Teehee Valley Solo Luigi Maze Room 2 Digspot 2"
TeeheeValleySoloLuigiMazeRoom1Block = "Teehee Valley Solo Luigi Maze Room 1 Block"
TeeheeValleyBeforeTrunkleDigspot = "Teehee Valley Before Trunkle Digspot"
TeeheeValleyTrunkleRoomDigspot = "Teehee Valley Trunkle Room Digspot"
SSChuckolaStorageRoomBlock1 = "S.S. Chuckola Storage Room Block 1"
SSChuckolaStorageRoomBlock2 = "S.S. Chuckola Storage Room Block 2"
LittleFungitownEmbassyRoomBlock = "Little Fungitown Embassy Room Block"
LittleFungitownEntranceRoomBlock = "Little Fungitown Entrance Room Block"
JokesEndPipeDigspot = "Joke's End Pipe Digspot"
JokesEndStaircaseDigspot = "Joke's End Staircase Digspot"
JokesEndWestOfFirstBoilerRoomBlock1 = "Joke's End West Of First Boiler Room Block 1"
JokesEndWestOfFirstBoilerRoomBlock2 = "Joke's End West Of First Boiler Room Block 2"
JokesEndFirstBoilerRoomDigspot1 = "Joke's End First Boiler Room Digspot 1"
JokesEndFirstBoilerRoomDigspot2 = "Joke's End First Boiler Room Digspot 2"
JokesEndFurnaceRoom1Block1 = "Joke's End Furnace Room 1 Block 1"
JokesEndFurnaceRoom1Block2 = "Joke's End Furnace Room 1 Block 2"
JokesEndFurnaceRoom1Block3 = "Joke's End Furnace Room 1 Block 3"
JokesEndNortheastOfBoilerRoom1Block = "Joke's End Northeast Of Boiler Room 1 Block"
JokesEndNortheastOfBoilerRoom3Digspot = "Joke's End Northeast Of Boiler Room 3 Digspot"
JokesEndNortheastOfBoilerRoom2Block1 = "Joke's End Northeast Of Boiler Room 2 Block"
JokesEndNortheastOfBoilerRoom2Block2 = "Joke's End Northeast Of Boiler Room 2 Digspot"
JokesEndSecondFloorWestRoomBlock1 = "Joke's End Second Floor West Room Block 1"
JokesEndSecondFloorWestRoomBlock2 = "Joke's End Second Floor West Room Block 2"
JokesEndSecondFloorWestRoomBlock3 = "Joke's End Second Floor West Room Block 3"
JokesEndSecondFloorWestRoomBlock4 = "Joke's End Second Floor West Room Block 4"
JokesEndSecondFloorEastRoomDigspot = "Joke's End Second Floor East Room Digspot"
JokesEndFinalSplitUpRoomDigspot = "Joke's End Final Split Up Room Digspot"
JokesEndSouthOfBridgeRoomBlock = "Joke's End South Of Bridge Room Block"
JokesEndSoloLuigiRoom1Block = "Joke's End Solo Luigi Room 1 Block"
JokesEndSoloLuigiRoom1Digspot = "Joke's End Solo Luigi Room 1 Digspot"
JokesEndSoloMarioFinalRoomBlock1 = "Joke's End Solo Mario Final Room Block 1"
JokesEndSoloMarioFinalRoomBlock2 = "Joke's End Solo Mario Final Room Block 2"
JokesEndSoloMarioFinalRoomBlock3 = "Joke's End Solo Mario Final Room Block 3"
JokesEndSoloLuigiRoom2Digspot = "Joke's End Solo Luigi Room 2 Digspot"
JokesEndSoloMarioRoom1Digspot = "Joke's End Solo Mario Room 1 Digspot"
JokesEndSoloMarioRoom2Block1 = "Joke's End Solo Mario Room 2 Block 1"
JokesEndSoloMarioRoom2Block2 = "Joke's End Solo Mario Room 2 Block 2"
JokesEndSoloMarioRoom2Block3 = "Joke's End Solo Mario Room 2 Block 3"
JokesEndSecondBoilerRoomDigspot1 = "Joke's End Second Boiler Room Digspot 1"
JokesEndSecondBoilerRoomDigspot2 = "Joke's End Second Boiler Room Digspot 2"
JokesEndNorthOfSecondBoilerRoomBlock1 = "Joke's End North Of Second Boiler Room Block 1"
JokesEndNorthOfSecondBoilerRoomBlock2 = "Joke's End North Of Second Boiler Room Block 2"
WinkleAreaColloseumDigspot = "Winkle Area Colloseum Digspot"
HoohooMountainFountainRoom2Block = "Hoohoo Mountain Fountain Room 2 Block"
HoohooMountainFountainRoom2Digspot = "Hoohoo Mountain Fountain Room 2 Digspot"
HoohooMountainPastHoohoorosConnectorRoomDigspot1 = "Hoohoo Mountain Past Hoohooros Connector Room Digspot 1"
HoohooMountainPastHoohoorosConnectorRoomBlock = "Hoohoo Mountain Past Hoohooros Connector Room Block"
HoohooMountainPastHoohoorosConnectorRoomDigspot2 = "Hoohoo Mountain Past Hoohooros Connector Room Digspot 2"
JokesEndBeforeJojoraRoomBlock1 = "Joke's End Before Jojora Room Block 1"
JokesEndBeforeJojoraRoomBlock2 = "Joke's End Before Jojora Room Block 2"
JokesEndBeforeJojoraRoomDigspot = "Joke's End Before Jojora Room Digspot"
JokesEndJojoraRoomDigspot = "Joke's End Jojora Room Digspot"
BeanbeanOutskirtsBeforeHarhallDigspot1 = "Beanbean Outskirts Before Harhall Digspot 1"
BeanbeanOutskirtsBeforeHarhallDigspot2 = "Beanbean Outskirts Before Harhall Digspot 2"
BeanbeanOutskirtsBroochGuardsRoomDigspot1 = "Beanbean Outskirts Brooch Guards Room Digspot 1"
BeanbeanOutskirtsBroochGuardsRoomDigspot2 = "Beanbean Outskirts Brooch Guards Room Digspot 2"
BeanbeanOutskirtsChateauEntranceDigspot1 = "Beanbean Outskirts Chateau Entrance Digspot 1"
BeanbeanOutskirtsChateauEntranceDigspot2 = "Beanbean Outskirts Chateau Entrance Digspot 2"
BeanbeanOutskirtsSouthOfHooniversityGuardsDigspot1 = "Beanbean Outskirts South of Hooniversity Guards Digspot 1"
BeanbeanOutskirtsSouthOfHooniversityGuardsDigspot2 = "Beanbean Outskirts South of Hooniversity Guards Digspot 2"
BeanbeanOutskirtsSouthOfHooniversityGuardsDigspot3 = "Beanbean Outskirts South of Hooniversity Guards Digspot 3"
OutsideWoohooHooniversityBlock = "Outside Woohoo Hooniversity Block"
BeanbeanOutskirtsEntranceToHoohooMountainBaseDigspot1 = (
"Beanbean Outskirts Entrance to Hoohoo Mountain Base Digspot 1"
)
BeanbeanOutskirtsEntranceToHoohooMountainBaseDigspot2 = (
"Beanbean Outskirts Entrance to Hoohoo Mountain Base Digspot 2"
)
WoohooHooniversitySoloMarioBarrelAreaBlock1 = "Woohoo Hooniversity Solo Mario Barrel Area Block 1"
WoohooHooniversitySoloMarioBarrelAreaBlock2 = "Woohoo Hooniversity Solo Mario Barrel Area Block 2"
WoohooHooniversitySoloMarioBarrelAreaBlock3 = "Woohoo Hooniversity Solo Mario Barrel Area Block 3"
BeanbeanOutskirtsPipe2RoomDigspot = "Beanbean Outskirts Pipe 2 Room Digspot"
BeanbeanOutskirtsPipe4RoomDigspot = "Beanbean Outskirts Pipe 4 Room Digspot"
BeanbeanCastleTownBeanletReward = "Beanbean Castle Town Beanlet Reward"
HoohooVillageMoleBehindTurtle = "Hoohoo Village Mole Behind Turtle"
HoohooMountainBaseMoleNearTeeheeValley = "Hoohoo Mountain Base Mole Near Teehee Valley"
BeanbeanOutskirtsSoloLuigiCaveMole = "Beanbean Outskirts Solo Luigi Cave Mole"
BeanbeanOutskirtsFarmRoomMoleReward1 = "Beanbean Outskirts Farm Room Mole Reward 1"
BeanbeanOutskirtsFarmRoomMoleReward2 = "Beanbean Outskirts Farm Room Mole Reward 2"
JokesEndMoleReward1 = "Joke's End Mole Reward 1"
JokesEndMoleReward2 = "Joke's End Mole Reward 2"
NorthOceanWhirlpoolMole = "North Ocean Whirlpool Mole"
BeanbeanOutskirtsNESoloMarioMole1 = "Beanbean Outskirts NE Solo Mario Mole 1"
HoohooVillageHammers = "Hoohoo Village Hammers"
BeanbeanOutskirtsSuperHammerUpgrade = "Beanbean Outskirts Super Hammer Upgrade"
BeanbeanOutskirtsUltraHammerUpgrade = "Beanbean Outskirts Ultra Hammer Upgrade"
OhoOasisFirebrand = "Oho Oasis Firebrand"
OhoOasisThunderhand = "Oho Oasis Thunderhand"
ChucklehuckWoodsRedChuckolaFruit = "Chucklehuck Woods Red Chuckola Fruit"
ChucklehuckWoodsWhiteChuckolaFruit = "Chucklehuck Woods White Chuckola Fruit"
ChucklehuckWoodsPurpleChuckolaFruit = "Chucklehuck Woods Purple Chuckola Fruit"
SSChuckolaMembershipCard = "S.S. Chuckola Membership Card"
WinkleAreaWinkleCard = "Winkle Area Winkle Card"
BeanbeanCastlePeachsExtraDress = "Beanbean Castle Peach's Extra Dress"
BeanbeanCastleFakeBeastar = "Beanbean Castle Fake Beanstar"
BeanbeanCastleTownBeanlet1 = "Beanbean Castle Town Beanlet 1"
BeanbeanCastleTownBeanlet2 = "Beanbean Castle Town Beanlet 2"
BeanbeanCastleTownBeanlet3 = "Beanbean Castle Town Beanlet 3"
BeanbeanCastleTownBeanlet4 = "Beanbean Castle Town Beanlet 4"
BeanbeanCastleTownBeanlet5 = "Beanbean Castle Town Beanlet 5"
BeanbeanCastleTownBeanstone1 = "Beanbean Castle Town Beanstone 1"
BeanbeanCastleTownBeanstone2 = "Beanbean Castle Town Beanstone 2"
BeanbeanCastleTownBeanstone3 = "Beanbean Castle Town Beanstone 3"
BeanbeanCastleTownBeanstone4 = "Beanbean Castle Town Beanstone 4"
BeanbeanCastleTownBeanstone5 = "Beanbean Castle Town Beanstone 5"
BeanbeanCastleTownBeanstone6 = "Beanbean Castle Town Beanstone 6"
BeanbeanCastleTownBeanstone7 = "Beanbean Castle Town Beanstone 7"
BeanbeanCastleTownBeanstone8 = "Beanbean Castle Town Beanstone 8"
BeanbeanCastleTownBeanstone9 = "Beanbean Castle Town Beanstone 9"
BeanbeanCastleTownBeanstone10 = "Beanbean Castle Town Beanstone 10"
YoshiTheaterBlueYoshi = "Yoshi Theater Blue Yoshi"
YoshiTheaterRedYoshi = "Yoshi Theater Red Yoshi"
YoshiTheaterGreenYoshi = "Yoshi Theater Green Yoshi"
YoshiTheaterYellowYoshi = "Yoshi Theater Yellow Yoshi"
YoshiTheaterPurpleYoshi = "Yoshi Theater Purple Yoshi"
YoshiTheaterOrangeYoshi = "Yoshi Theater Orange Yoshi"
YoshiTheaterAzureYoshi = "Yoshi Theater Azure Yoshi"
BeanbeanCastleBeanbeanBrooch = "Beanbean Castle Beanbean Brooch"
BeanbeanOutskirtsSecretScroll1 = "Beanbean Outskirts Secret Scroll 1"
BeanbeanOutskirtsSecretScroll2 = "Beanbean Outskirts Secret Scroll 2"
BeanbeanOutskirtsBeanFruit1 = "Beanbean Outskirts Bean Fruit 1"
BeanbeanOutskirtsBeanFruit2 = "Beanbean Outskirts Bean Fruit 2"
BeanbeanOutskirtsBeanFruit3 = "Beanbean Outskirts Bean Fruit 3"
BeanbeanOutskirtsBeanFruit4 = "Beanbean Outskirts Bean Fruit 4"
BeanbeanOutskirtsBeanFruit5 = "Beanbean Outskirts Bean Fruit 5"
BeanbeanOutskirtsBeanFruit6 = "Beanbean Outskirts Bean Fruit 6"
BeanbeanOutskirtsBeanFruit7 = "Beanbean Outskirts Bean Fruit 7"
HoohooMountainPeasleysRose = "Hoohoo Mountain Peasley's Rose"
ChateauGreenGoblet = "Chateau Green Goblet"
ChateauRedGoblet = "Chateau Red Goblet"
GwarharLagoonRedPearlBean = "Gwarhar Lagoon Red Pearl Bean"
GwarharLagoonGreenPearlBean = "Gwarhar Lagoon Green Pearl Bean"
GwarharLagoonSpangle = "Gwarhar Lagoon Spangle"
BeanstarPieceWinkleArea = "Beanstar Piece Winkle Area"
BeanstarPieceHarhall = "Beanstar Piece Harhall"
BeanstarPieceYoshiTheater = "Beanstar Piece Yoshi Theater"
BeanstarPieceHermie = "Beanstar Piece Hermie"
ShopStartingFlag1 = "Shop Starting Flag 1"
ShopStartingFlag2 = "Shop Starting Flag 2"
ShopStartingFlag3 = "Shop Starting Flag 3"
ShopChuckolatorFlag = "Shop Chuckolator Flag"
ShopMomPiranhaFlag1 = "Shop Mom Piranha Flag 1"
ShopMomPiranhaFlag2 = "Shop Mom Piranha Flag 2"
ShopMomPiranhaFlag3 = "Shop Mom Piranha Flag 3"
ShopMomPiranhaFlag4 = "Shop Mom Piranha Flag 4"
ShopPeachKidnappedFlag1 = "Shop Enter Fungitown Flag 1"
ShopPeachKidnappedFlag2 = "Shop Enter Fungitown Flag 2"
FungitownShopStartingFlag1 = "Fungitown Shop Starting Flag 1"
FungitownShopStartingFlag2 = "Fungitown Shop Starting Flag 2"
FungitownShopStartingFlag3 = "Fungitown Shop Starting Flag 3"
FungitownShopStartingFlag4 = "Fungitown Shop Starting Flag 4"
FungitownShopStartingFlag5 = "Fungitown Shop Starting Flag 5"
FungitownShopStartingFlag6 = "Fungitown Shop Starting Flag 6"
FungitownShopStartingFlag7 = "Fungitown Shop Starting Flag 7"
FungitownShopStartingFlag8 = "Fungitown Shop Starting Flag 8"
ShopBeanstarCompleteFlag1 = "Shop Beanstar Complete Flag 1"
ShopBeanstarCompleteFlag2 = "Shop Beanstar Complete Flag 2"
ShopBeanstarCompleteFlag3 = "Shop Beanstar Complete Flag 3"
FungitownShopBeanstarCompleteFlag = "Fungitown Shop Beanstar Complete Flag"
ShopBirdoFlag = "Shop Birdo Flag"
FungitownShopBirdoFlag = "Fungitown Shop Birdo Flag"
CoffeeShopBrewReward1 = "Coffee Shop Brew Reward 1"
CoffeeShopBrewReward2 = "Coffee Shop Brew Reward 2"
CoffeeShopBrewReward3 = "Coffee Shop Brew Reward 3"
CoffeeShopBrewReward4 = "Coffee Shop Brew Reward 4"
CoffeeShopBrewReward5 = "Coffee Shop Brew Reward 5"
CoffeeShopBrewReward6 = "Coffee Shop Brew Reward 6"
CoffeeShopBrewReward7 = "Coffee Shop Brew Reward 7"
CoffeeShopWoohooBlend = "Coffee Shop Woohoo Blend"
CoffeeShopHoohooBlend = "Coffee Shop Hoohoo Blend"
CoffeeShopChuckleBlend = "Coffee Shop Chuckle Blend"
CoffeeShopTeeheeBlend = "Coffee Shop Teehee Blend"
CoffeeShopHoolumbian = "Coffee Shop Hoolumbian"
CoffeeShopChuckoccino = "Coffee Shop Chuckoccino"
CoffeeShopTeeheespresso = "Coffee Shop Teeheespresso"
PantsShopStartingFlag1 = "Pants Shop Starting Flag 1"
PantsShopStartingFlag2 = "Pants Shop Starting Flag 2"
PantsShopStartingFlag3 = "Pants Shop Starting Flag 3"
PantsShopChuckolatorFlag1 = "Pants Shop Chuckolator Flag 1"
PantsShopChuckolatorFlag2 = "Pants Shop Chuckolator Flag 2"
PantsShopChuckolatorFlag3 = "Pants Shop Chuckolator Flag 3"
PantsShopMomPiranhaFlag1 = "Pants Shop Mom Piranha Flag 1"
PantsShopMomPiranhaFlag2 = "Pants Shop Mom Piranha Flag 2"
PantsShopMomPiranhaFlag3 = "Pants Shop Mom Piranha Flag 3"
PantsShopPeachKidnappedFlag1 = "Pants Shop Enter Fungitown Flag 1"
PantsShopPeachKidnappedFlag2 = "Pants Shop Enter Fungitown Flag 2"
PantsShopPeachKidnappedFlag3 = "Pants Shop Enter Fungitown Flag 3"
PantsShopBeanstarCompleteFlag1 = "Pants Shop Beanstar Complete Flag 1"
PantsShopBeanstarCompleteFlag2 = "Pants Shop Beanstar Complete Flag 2"
PantsShopBeanstarCompleteFlag3 = "Pants Shop Beanstar Complete Flag 3"
PantsShopBirdoFlag1 = "Pants Shop Birdo Flag 1"
PantsShopBirdoFlag2 = "Pants Shop Birdo Flag 2"
PantsShopBirdoFlag3 = "Pants Shop Birdo Flag 3"
FungitownPantsShopStartingFlag1 = "Fungitown Pants Shop Starting Flag 1"
FungitownPantsShopStartingFlag2 = "Fungitown Pants Shop Starting Flag 2"
FungitownPantsShopStartingFlag3 = "Fungitown Pants Shop Starting Flag 3"
FungitownPantsShopBeanstarCompleteFlag1 = "Fungitown Pants Shop Beanstar Complete Flag 1"
FungitownPantsShopBeanstarCompleteFlag2 = "Fungitown Pants Shop Beanstar Complete Flag 2"
FungitownPantsShopBirdoFlag1 = "Fungitown Pants Shop Birdo Flag 1"
FungitownPantsShopBirdoFlag2 = "Fungitown Pants Shop Birdo Flag 2"
BeanbeanOutskirtsNESoloMarioMole2 = "Beanbean Outskirts NE Solo Mario Mole 2"
GwarharLagoonSpangleReward = "Gwarhar Lagoon Spangle Reward"
BowsersCastleEntranceBlock1 = "Bowser's Castle Entrance Block 1"
BowsersCastleEntranceBlock2 = "Bowser's Castle Entrance Block 2"
BowsersCastleEntranceDigspot = "Bowser's Castle Entrance Digspot"
BowsersCastleIggyMortonHallwayBlock1 = "Bowser's Castle Iggy & Morton Hallway Block 1"
BowsersCastleIggyMortonHallwayBlock2 = "Bowser's Castle Iggy & Morton Hallway Block 2"
BowsersCastleIggyMortonHallwayDigspot = "Bowser's Castle Iggy & Morton Hallway Digspot"
BowsersCastleAfterMortonBlock = "Bowser's Castle After Morton Block"
BowsersCastleLudwigRoyHallwayBlock1 = "Bowser's Castle Ludwig & Roy Hallway Block 1"
BowsersCastleLudwigRoyHallwayBlock2 = "Bowser's Castle Ludwig & Roy Hallway Block 2"
BowsersCastleRoyCorridorBlock1 = "Bowser's Castle Roy Corridor Block 1"
BowsersCastleRoyCorridorBlock2 = "Bowser's Castle Roy Corridor Block 2"
BowsersCastleWendyLarryHallwayDigspot = "Bowser's Castle Wendy & Larry Hallway Digspot"
BowsersCastleBeforeFawfulFightBlock1 = "Bowser's Castle Before Fawful Fight Block 1"
BowsersCastleBeforeFawfulFightBlock2 = "Bowser's Castle Before Fawful Fight Block 2"
BowsersCastleGreatDoorBlock1 = "Bowser's Castle Great Door Block 1"
BowsersCastleGreatDoorBlock2 = "Bowser's Castle Great Door Block 2"
BowsersCastleMortonRoom1Digspot = "Bowser's Castle Morton Room 1 Digspot"
BowsersCastleLemmyRoom1Block = "Bowser's Castle Lemmy Room 1 Block"
BowsersCastleLemmyRoom1Digspot = "Bowser's Castle Lemmy Room 1 Digspot"
BowsersCastleLudwigRoom1Block = "Bowser's Castle Ludwig Room 1 Block"
BowsersCastleMiniMarioSidescrollerBlock1 = "Bowser's Castle Mini Mario Sidescroller Block 1"
BowsersCastleMiniMarioSidescrollerBlock2 = "Bowser's Castle Mini Mario Sidescroller Block 2"
BowsersCastleMiniMarioMazeBlock1 = "Bowser's Castle Mini Mario Maze Block 1"
BowsersCastleMiniMarioMazeBlock2 = "Bowser's Castle Mini Mario Maze Block 2"
BowsersCastleBeforeWendyFightBlock1 = "Bowser's Castle Before Wendy Fight Block 1"
BowsersCastleBeforeWendyFightBlock2 = "Bowser's Castle Before Wendy Fight Block 2"
BowsersCastleLarryRoomBlock = "Bowser's Castle Larry Room Block"
BowsersCastleLemmyRoomMole = "Bowser's Castle Lemmy Room Mole"
SurfMinigame = "Surf Minigame"
BeanbeanOutskirtsThunderHandMole = "Beanbean Outskirts Thunderhand Mole"
BadgeShopMomPiranhaFlag1 = "Badge Shop Mom Piranha Flag 1"
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"
BeanbeanOutskirtsNWCoinBlock = "Beanbean Outskirts NW Coin Block"
BeanbeanOutskirtsSRoom1CoinBlock = "Beanbean Outskirts S Room 1 Coin Block"
BeanbeanOutskirtsSRoom2CoinBlock = "Beanbean Outskirts S Room 2 Coin Block"
ChateauPoppleRoomCoinBlock1 = "Chateau Popple Room Coin Block 1"
ChateauPoppleRoomCoinBlock2 = "Chateau Popple Room Coin Block 2"
ChucklehuckWoodsCaveRoom1CoinBlock = "Chucklehuck Woods Cave Room 1 Coin Block"
ChucklehuckWoodsCaveRoom2CoinBlock = "Chucklehuck Woods Cave Room 2 Coin Block"
ChucklehuckWoodsCaveRoom3CoinBlock = "Chucklehuck Woods Cave Room 3 Coin Block"
ChucklehuckWoodsPipe5RoomCoinBlock = "Chucklehuck Woods Pipe 5 Room Coin Block"
ChucklehuckWoodsRoom7CoinBlock = "Chucklehuck Woods Room 7 Coin Block"
ChucklehuckWoodsAfterChucklerootCoinBlock = "Chucklehuck Woods After Chuckleroot Coin Block"
ChucklehuckWoodsKoopaRoomCoinBlock = "Chucklehuck Woods Koopa Room Coin Block"
ChucklehuckWoodsWinkleAreaCaveCoinBlock = "Chucklehuck Woods Winkle Area Cave Coin Block"
SewersPrisonRoomCoinBlock = "Sewers Prison Room Coin Block"
TeeheeValleyPastUltraHammerRocksCoinBlock = "Teehee Valley Past Ultra Hammer Rocks Coin Block"
SSChuckolaStorageRoomCoinBlock1 = "S.S. Chuckola Storage Room Coin Block 1"
SSChuckolaStorageRoomCoinBlock2 = "S.S. Chuckola Storage Room Coin Block 2"
GwarharLagoonFirstUnderwaterAreaRoom2CoinBlock = "Gwarhar Lagoon First Underwater Area Room 2 Coin Block"
JokesEndSecondFloorWestRoomCoinBlock = "Joke's End Second Floor West Room Coin Block"
JokesEndNorthofBridgeRoomCoinBlock = "Joke's End North of Bridge Room Coin Block"

299
worlds/mlss/Options.py Normal file
View File

@ -0,0 +1,299 @@
from Options import Choice, Toggle, StartInventoryPool, PerGameCommonOptions, Range
from dataclasses import dataclass
class BowsersCastleSkip(Toggle):
"""
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"
class ExtraPipes(Toggle):
"""
Gives the player access to pipes 1, 3, 4, and 6 from the start.
"""
display_name = "Start With Extra Pipes"
class SkipMinecart(Toggle):
"""
Skip the minecart minigame that leads you through Hoohoo Mountain Base.
This will remove the 1 location in the minecart cave from the location pool.
"""
display_name = "Skip Minecart Minigame"
class DisableSurf(Toggle):
"""
Remove the surf minigame location from the location pool.
"""
display_name = "Disable Surf Minigame"
class MusicOptions(Choice):
"""
Choose if you want to randomize or disable music.
default: Music will be untouched.
randomize: Music will be randomized.
disable: All music will be disabled. No music will play throughout the entire game.
"""
display_name = "Music Options"
option_default = 0
option_randomize = 1
option_disable = 2
default = 0
class RandomSounds(Toggle):
"""
Randomizes every sound in the game, minus a select few that can softlock the game.
"""
display_name = "Randomize Sounds"
class MarioColor(Choice):
"""
This changes the color of Mario's hat, as well as some key colors that are red including UI etc.
"""
display_name = "Mario's Color"
option_red = 0
option_green = 1
option_blue = 2
option_cyan = 3
option_yellow = 4
option_orange = 5
option_purple = 6
option_pink = 7
option_black = 8
option_white = 9
option_silhouette = 10
option_chaos = 11
option_true_chaos = 12
default = 0
class LuigiColor(Choice):
"""
This changes the color of Luigi's hat, as well as some key colors that are green including UI etc.
"""
display_name = "Luigi's Color"
option_red = 0
option_green = 1
option_blue = 2
option_cyan = 3
option_yellow = 4
option_orange = 5
option_purple = 6
option_pink = 7
option_black = 8
option_white = 9
option_silhouette = 10
option_chaos = 11
option_true_chaos = 12
default = 1
class MarioPants(Choice):
"""
This changes the color of Mario's trousers.
"""
display_name = "Mario's Pants Color"
option_vanilla = 0
option_red = 1
option_green = 2
option_blue = 3
option_cyan = 4
option_yellow = 5
option_orange = 6
option_purple = 7
option_pink = 8
option_black = 9
option_white = 10
option_chaos = 11
default = 0
class LuigiPants(Choice):
"""
This changes the color of Luigi's trousers.
"""
display_name = "Luigi's Pants Color"
option_vanilla = 0
option_red = 1
option_green = 2
option_blue = 3
option_cyan = 4
option_yellow = 5
option_orange = 6
option_purple = 7
option_pink = 8
option_black = 9
option_white = 10
option_chaos = 11
default = 0
class RandomizeEnemies(Choice):
"""
Randomize all normal enemy encounters in the game.
If Bowser's castle skip is enabled, then enemies from Bowser's Castle will not be included.
Disabled: Enemies will not be randomized.
Vanilla Groups: Vanilla enemy groups will be shuffled with each other. Custom enemy groups will not be made.
Custom Groups: Custom enemy groups will be made and shuffled. Some enemy groups will only be semi-random,
including groups with flying enemies or pestnuts in them.
"""
display_name = "Randomize Enemies"
option_disabled = 0
option_vanilla_groups = 1
option_custom_groups = 2
default = 0
class RandomizeBosses(Choice):
"""
Randomize all boss encounters in the game.
If Bowser's castle skip is enabled then bosses from Bowser's Castle will not be included.
Some bosses are not randomized due to flags, and story (such as the final boss).
Boss Only: Bosses will only be swapped with another boss.
Boss Normal: Bosses can be swapped with normal enemy encounters.
"""
display_name = "Randomize Bosses"
option_disabled = 0
option_boss_only = 1
option_boss_normal = 2
default = 0
class ScaleStats(Toggle):
"""
This scales enemy HP, POW, DEF, and XP to vanilla values.
This setting is intended for use with the Enemy Randomizer and is Recommended to turn on.
If you are not using the Enemy Randomizer the effects will be minimal.
"""
display_name = "Scale Enemy Stats"
class XPMultiplier(Range):
"""
This will multiply any XP you receive in battle by the chosen multiplier.
"""
display_name = "XP Multiplier"
range_start = 0
range_end = 4
default = 1
class TattleHp(Toggle):
"""
This will display the enemies' current and max health while in battle.
"""
display_name = "Tattle HP"
class RandomizeBackgrounds(Toggle):
"""
This randomizes the background image in battles.
"""
display_name = "Randomize Battle Backgrounds"
class HiddenVisible(Choice):
"""
This makes any hidden blocks in the game into regular item blocks and vice versa.
Disabled: Hidden blocks will remain invisible.
Hidden Visible: Hidden blocks will turn visible to the player.
Blocks Invisible: All item blocks will turn invisible. Hidden blocks will also remain invisible.
"""
display_name = "Item Block Visibility"
option_disabled = 0
option_hidden_visible = 1
option_blocks_invisible = 2
default = 0
class Coins(Toggle):
"""
Add all coin blocks in the game to the location pool.
"""
display_name = "Coin Blocks"
class HarhallsPants(Toggle):
"""
This will remove the Harhall's Pants check from the pool.
"""
display_name = "Remove Harhall's Pants"
class DifficultLogic(Toggle):
"""
This adjusts the logic to be more difficult in a few areas,
allowing for the logic to account for players getting to certain areas in unintended ways.
Enable at your own risk, this is not an option made for beginners.
"""
display_name = "Difficult Logic"
class ChuckleBeans(Choice):
"""
Choose how you want chuckle bean digspots to be randomized.
An amount of chuckle beans will be removed from the item pool,
equal to the amount of locations removed by the setting that you choose.
None: No chuckle bean digspots will be added into the location pool.
Only Visible: Only chuckle bean digspots clearly marked with an X will be added into the location pool.
All: All chuckle bean digspots will be added into the location pool.
"""
display_name = "Chuckle Beans"
option_none = 0
option_only_visible = 1
option_all = 2
default = 2
@dataclass
class MLSSOptions(PerGameCommonOptions):
start_inventory_from_pool: StartInventoryPool
coins: Coins
difficult_logic: DifficultLogic
castle_skip: BowsersCastleSkip
extra_pipes: ExtraPipes
skip_minecart: SkipMinecart
disable_surf: DisableSurf
harhalls_pants: HarhallsPants
block_visibility: HiddenVisible
chuckle_beans: ChuckleBeans
music_options: MusicOptions
randomize_sounds: RandomSounds
randomize_enemies: RandomizeEnemies
randomize_bosses: RandomizeBosses
randomize_backgrounds: RandomizeBackgrounds
scale_stats: ScaleStats
xp_multiplier: XPMultiplier
tattle_hp: TattleHp
mario_color: MarioColor
luigi_color: LuigiColor
mario_pants: MarioPants
luigi_pants: LuigiPants

323
worlds/mlss/Regions.py Normal file
View File

@ -0,0 +1,323 @@
import typing
from BaseClasses import Region, Entrance
from .Locations import (
MLSSLocation,
mainArea,
chucklehuck,
castleTown,
startingFlag,
chuckolatorFlag,
piranhaFlag,
kidnappedFlag,
beanstarFlag,
birdoFlag,
surfable,
hooniversity,
gwarharEntrance,
gwarharMain,
fungitown,
fungitownBeanstar,
fungitownBirdo,
teeheeValley,
winkle,
sewers,
airport,
bowsers,
bowsersMini,
jokesEntrance,
jokesMain,
theater,
booStatue,
oasis,
postJokes,
baseUltraRocks,
coins,
)
from . import StateLogic
if typing.TYPE_CHECKING:
from . import MLSSWorld
def create_regions(world: "MLSSWorld", excluded: typing.List[str]):
menu_region = Region("Menu", world.player, world.multiworld)
world.multiworld.regions.append(menu_region)
create_region(world, "Main Area", mainArea, excluded)
create_region(world, "Chucklehuck Woods", chucklehuck, excluded)
create_region(world, "Beanbean Castle Town", castleTown, excluded)
create_region(world, "Shop Starting Flag", startingFlag, excluded)
create_region(world, "Shop Chuckolator Flag", chuckolatorFlag, excluded)
create_region(world, "Shop Mom Piranha Flag", piranhaFlag, excluded)
create_region(world, "Shop Enter Fungitown Flag", kidnappedFlag, excluded)
create_region(world, "Shop Beanstar Complete Flag", beanstarFlag, excluded)
create_region(world, "Shop Birdo Flag", birdoFlag, excluded)
create_region(world, "Surfable", surfable, excluded)
create_region(world, "Hooniversity", hooniversity, excluded)
create_region(world, "GwarharEntrance", gwarharEntrance, excluded)
create_region(world, "GwarharMain", gwarharMain, excluded)
create_region(world, "TeeheeValley", teeheeValley, excluded)
create_region(world, "Winkle", winkle, excluded)
create_region(world, "Sewers", sewers, excluded)
create_region(world, "Airport", airport, excluded)
create_region(world, "JokesEntrance", jokesEntrance, excluded)
create_region(world, "JokesMain", jokesMain, excluded)
create_region(world, "PostJokes", postJokes, excluded)
create_region(world, "Theater", theater, excluded)
create_region(world, "Fungitown", fungitown, excluded)
create_region(world, "Fungitown Shop Beanstar Complete Flag", fungitownBeanstar, excluded)
create_region(world, "Fungitown Shop Birdo Flag", fungitownBirdo, excluded)
create_region(world, "BooStatue", booStatue, excluded)
create_region(world, "Oasis", oasis, excluded)
create_region(world, "BaseUltraRocks", baseUltraRocks, excluded)
if world.options.coins:
create_region(world, "Coins", coins, excluded)
if not world.options.castle_skip:
create_region(world, "Bowser's Castle", bowsers, excluded)
create_region(world, "Bowser's Castle Mini", bowsersMini, excluded)
def connect_regions(world: "MLSSWorld"):
names: typing.Dict[str, int] = {}
connect(world, names, "Menu", "Main Area")
if world.options.coins:
connect(world, names, "Main Area", "Coins")
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))
connect(
world,
names,
"Main Area",
"Hooniversity",
lambda state: StateLogic.canDig(state, world.player) and StateLogic.canMini(state, world.player),
)
connect(world, names, "Hooniversity", "Oasis")
connect(
world,
names,
"Main Area",
"TeeheeValley",
lambda state: StateLogic.super(state, world.player) or StateLogic.canDash(state, world.player),
)
connect(
world,
names,
"TeeheeValley",
"GwarharEntrance",
lambda state: StateLogic.membership(state, world.player) and StateLogic.fire(state, world.player),
)
connect(
world,
names,
"TeeheeValley",
"Oasis",
lambda state: StateLogic.membership(state, world.player) and StateLogic.fire(state, world.player),
)
connect(
world,
names,
"TeeheeValley",
"Fungitown",
lambda state: StateLogic.thunder(state, world.player)
and StateLogic.castleTown(state, world.player)
and StateLogic.rose(state, world.player),
)
connection = connect(
world,
names,
"Fungitown",
"Fungitown Shop Beanstar Complete Flag",
lambda state: StateLogic.pieces(state, world.player) or StateLogic.fungitown_birdo_shop(state, world.player),
True,
)
world.multiworld.register_indirect_condition(world.get_region("Fungitown Shop Birdo Flag"), connection)
connect(world, names, "Main Area", "Shop Starting Flag")
connection = connect(
world,
names,
"Shop Starting Flag",
"Shop Chuckolator Flag",
lambda state: (
StateLogic.brooch(state, world.player)
and StateLogic.fruits(state, world.player)
and (
StateLogic.thunder(state, world.player)
or StateLogic.fire(state, world.player)
or StateLogic.hammers(state, world.player)
)
)
or (
StateLogic.piranha_shop(state, world.player)
or StateLogic.fungitown_shop(state, world.player)
or StateLogic.star_shop(state, world.player)
or StateLogic.birdo_shop(state, world.player)
),
True,
)
world.multiworld.register_indirect_condition(world.get_region("Shop Mom Piranha Flag"), connection)
world.multiworld.register_indirect_condition(world.get_region("Shop Enter Fungitown Flag"), connection)
world.multiworld.register_indirect_condition(world.get_region("Shop Beanstar Complete Flag"), connection)
world.multiworld.register_indirect_condition(world.get_region("Shop Birdo Flag"), connection)
connection = connect(
world,
names,
"Shop Starting Flag",
"Shop Mom Piranha Flag",
lambda state: StateLogic.thunder(state, world.player)
or (
StateLogic.fungitown_shop(state, world.player)
or StateLogic.star_shop(state, world.player)
or StateLogic.birdo_shop(state, world.player)
),
True,
)
world.multiworld.register_indirect_condition(world.get_region("Shop Enter Fungitown Flag"), connection)
world.multiworld.register_indirect_condition(world.get_region("Shop Beanstar Complete Flag"), connection)
world.multiworld.register_indirect_condition(world.get_region("Shop Birdo Flag"), connection)
connection = connect(
world,
names,
"Shop Starting Flag",
"Shop Enter Fungitown Flag",
lambda state: StateLogic.fungitown(state, world.player)
or (StateLogic.star_shop(state, world.player) or StateLogic.birdo_shop(state, world.player)),
True,
)
world.multiworld.register_indirect_condition(world.get_region("Shop Beanstar Complete Flag"), connection)
world.multiworld.register_indirect_condition(world.get_region("Shop Birdo Flag"), connection)
connection = connect(
world,
names,
"Shop Starting Flag",
"Shop Beanstar Complete Flag",
lambda state: (
StateLogic.castleTown(state, world.player)
and StateLogic.pieces(state, world.player)
and StateLogic.rose(state, world.player)
)
or StateLogic.birdo_shop(state, world.player),
True,
)
world.multiworld.register_indirect_condition(world.get_region("Shop Birdo Flag"), connection)
connect(world, names, "Main Area", "Sewers", lambda state: StateLogic.rose(state, world.player))
connect(world, names, "Main Area", "Airport", lambda state: StateLogic.thunder(state, world.player))
connect(world, names, "Main Area", "Theater", lambda state: StateLogic.canDash(state, world.player))
connect(world, names, "Main Area", "Surfable", lambda state: StateLogic.surfable(state, world.player))
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, "PostJokes", "Bowser's Castle")
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, "Chucklehuck Woods", "Winkle", lambda state: StateLogic.canDash(state, world.player))
connect(
world,
names,
"Chucklehuck Woods",
"Beanbean Castle Town",
lambda state: StateLogic.fruits(state, world.player)
and (
StateLogic.hammers(state, world.player)
or StateLogic.fire(state, world.player)
or StateLogic.thunder(state, world.player)
),
)
if world.options.difficult_logic:
connect(world, names, "GwarharEntrance", "GwarharMain", lambda state: StateLogic.canDash(state, world.player))
connect(world, names, "JokesEntrance", "JokesMain", lambda state: StateLogic.canDig(state, world.player))
connect(
world,
names,
"Shop Starting Flag",
"Shop Birdo Flag",
lambda state: StateLogic.postJokes(state, world.player),
)
connect(
world,
names,
"Fungitown",
"Fungitown Shop Birdo Flag",
lambda state: StateLogic.postJokes(state, world.player),
)
else:
connect(
world,
names,
"GwarharEntrance",
"GwarharMain",
lambda state: StateLogic.canDash(state, world.player) and StateLogic.canCrash(state, world.player),
)
connect(
world,
names,
"JokesEntrance",
"JokesMain",
lambda state: StateLogic.canCrash(state, world.player) and StateLogic.canDig(state, world.player),
)
connect(
world,
names,
"Shop Starting Flag",
"Shop Birdo Flag",
lambda state: StateLogic.canCrash(state, world.player) and StateLogic.postJokes(state, world.player),
)
connect(
world,
names,
"Fungitown",
"Fungitown Shop Birdo Flag",
lambda state: StateLogic.canCrash(state, world.player) and StateLogic.postJokes(state, world.player),
)
def create_region(world: "MLSSWorld", name, locations, excluded):
ret = Region(name, world.player, world.multiworld)
for location in locations:
loc = MLSSLocation(world.player, location.name, location.id, ret)
if location.name in excluded:
continue
ret.locations.append(loc)
world.multiworld.regions.append(ret)
def connect(
world: "MLSSWorld",
used_names: typing.Dict[str, int],
source: str,
target: str,
rule: typing.Optional[typing.Callable] = None,
reach: typing.Optional[bool] = False,
) -> Entrance | None:
source_region = world.multiworld.get_region(source, world.player)
target_region = world.multiworld.get_region(target, world.player)
if target not in used_names:
used_names[target] = 1
name = target
else:
used_names[target] += 1
name = target + (" " * used_names[target])
connection = Entrance(world.player, name, source_region)
if rule:
connection.access_rule = rule
source_region.exits.append(connection)
connection.connect(target_region)
if reach:
return connection
else:
return None

437
worlds/mlss/Rom.py Normal file
View File

@ -0,0 +1,437 @@
import io
import json
import random
from . import Data
from typing import TYPE_CHECKING, Optional
from BaseClasses import Item, Location
from settings import get_settings
from worlds.Files import APProcedurePatch, APTokenMixin, APTokenTypes, APPatchExtension
from .Items import item_table
from .Locations import shop, badge, pants, location_table, hidden, all_locations
if TYPE_CHECKING:
from . import MLSSWorld
colors = [
Data.redHat,
Data.greenHat,
Data.blueHat,
Data.azureHat,
Data.yellowHat,
Data.orangeHat,
Data.purpleHat,
Data.pinkHat,
Data.blackHat,
Data.whiteHat,
Data.silhouetteHat,
Data.chaosHat,
Data.truechaosHat
]
cpants = [
Data.vanilla,
Data.redPants,
Data.greenPants,
Data.bluePants,
Data.azurePants,
Data.yellowPants,
Data.orangePants,
Data.purplePants,
Data.pinkPants,
Data.blackPants,
Data.whitePants,
Data.chaosPants
]
def get_base_rom_as_bytes() -> bytes:
with open(get_settings().mlss_options.rom_file, "rb") as infile:
base_rom_bytes = bytes(infile.read())
return base_rom_bytes
class MLSSPatchExtension(APPatchExtension):
game = "Mario & Luigi Superstar Saga"
@staticmethod
def randomize_music(caller: APProcedurePatch, rom: bytes):
options = json.loads(caller.get_file("options.json").decode("UTF-8"))
if options["music_options"] != 1:
return rom
stream = io.BytesIO(rom)
random.seed(options["seed"] + options["player"])
songs = []
stream.seek(0x21CB74)
for _ in range(50):
if stream.tell() == 0x21CBD8:
stream.seek(4, 1)
continue
temp = stream.read(4)
songs.append(temp)
random.shuffle(songs)
stream.seek(0x21CB74)
for _ in range(50):
if stream.tell() == 0x21CBD8:
stream.seek(4, 1)
continue
stream.write(songs.pop())
return stream.getvalue()
@staticmethod
def hidden_visible(caller: APProcedurePatch, rom: bytes):
options = json.loads(caller.get_file("options.json").decode("UTF-8"))
if options["block_visibility"] == 0:
return rom
stream = io.BytesIO(rom)
for location in all_locations:
stream.seek(location.id - 6)
b = stream.read(1)
if b[0] == 0x10 and options["block_visibility"] == 1:
stream.seek(location.id - 6)
stream.write(bytes([0x0]))
if b[0] == 0x0 and options["block_visibility"] == 2:
stream.seek(location.id - 6)
stream.write(bytes([0x10]))
return stream.getvalue()
@staticmethod
def randomize_sounds(caller: APProcedurePatch, rom: bytes):
options = json.loads(caller.get_file("options.json").decode("UTF-8"))
if options["randomize_sounds"] != 1:
return rom
stream = io.BytesIO(rom)
random.seed(options["seed"] + options["player"])
fresh_pointers = Data.sounds
pointers = Data.sounds
random.shuffle(pointers)
stream.seek(0x21CC44, 0)
for i in range(354):
current_position = stream.tell()
value = int.from_bytes(stream.read(3), "little")
if value in fresh_pointers:
stream.seek(current_position)
stream.write(pointers.pop().to_bytes(3, "little"))
stream.seek(1, 1)
return stream.getvalue()
@staticmethod
def enemy_randomize(caller: APProcedurePatch, rom: bytes):
options = json.loads(caller.get_file("options.json").decode("UTF-8"))
if options["randomize_bosses"] == 0 and options["randomize_enemies"] == 0:
return rom
enemies = [pos for pos in Data.enemies if pos not in Data.bowsers] if options["castle_skip"] else Data.enemies
bosses = [pos for pos in Data.bosses if pos not in Data.bowsers] if options["castle_skip"] else Data.bosses
stream = io.BytesIO(rom)
random.seed(options["seed"] + options["player"])
if options["randomize_bosses"] == 1 or (options["randomize_bosses"] == 2) and options["randomize_enemies"] == 0:
raw = []
for pos in bosses:
stream.seek(pos + 1)
raw += [stream.read(0x1F)]
random.shuffle(raw)
for pos in bosses:
stream.seek(pos + 1)
stream.write(raw.pop())
if options["randomize_enemies"] == 1:
raw = []
for pos in enemies:
stream.seek(pos + 1)
raw += [stream.read(0x1F)]
if options["randomize_bosses"] == 2:
for pos in bosses:
stream.seek(pos + 1)
raw += [stream.read(0x1F)]
random.shuffle(raw)
for pos in enemies:
stream.seek(pos + 1)
stream.write(raw.pop())
if options["randomize_bosses"] == 2:
for pos in bosses:
stream.seek(pos + 1)
stream.write(raw.pop())
return stream.getvalue()
enemies_raw = []
groups = []
if options["randomize_enemies"] == 0:
return stream.getvalue()
if options["randomize_bosses"] == 2:
for pos in bosses:
stream.seek(pos + 1)
groups += [stream.read(0x1F)]
for pos in enemies:
stream.seek(pos + 8)
for _ in range(6):
enemy = int.from_bytes(stream.read(1))
if enemy > 0:
stream.seek(1, 1)
flag = int.from_bytes(stream.read(1))
if flag == 0x7:
break
if flag in [0x0, 0x2, 0x4]:
if enemy not in Data.pestnut and enemy not in Data.flying:
enemies_raw += [enemy]
stream.seek(1, 1)
else:
stream.seek(3, 1)
random.shuffle(enemies_raw)
chomp = False
for pos in enemies:
stream.seek(pos + 8)
for _ in range(6):
enemy = int.from_bytes(stream.read(1))
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))
if flag not in [0x0, 0x2, 0x4]:
stream.seek(1, 1)
continue
stream.seek(-3, 1)
stream.write(bytes([enemies_raw.pop()]))
stream.seek(1, 1)
stream.write(bytes([0x6]))
stream.seek(1, 1)
else:
stream.seek(3, 1)
stream.seek(pos + 1)
raw = stream.read(0x1F)
if chomp:
raw = raw[0:3] + bytes([0x67, 0xAB, 0x28, 0x08]) + raw[7:]
else:
raw = raw[0:3] + bytes([0xEE, 0x2C, 0x28, 0x08]) + raw[7:]
groups += [raw]
chomp = False
random.shuffle(groups)
arr = enemies
if options["randomize_bosses"] == 2:
arr += bosses
for pos in arr:
stream.seek(pos + 1)
stream.write(groups.pop())
return stream.getvalue()
class MLSSProcedurePatch(APProcedurePatch, APTokenMixin):
game = "Mario & Luigi Superstar Saga"
hash = "4b1a5897d89d9e74ec7f630eefdfd435"
patch_file_ending = ".apmlss"
result_file_ending = ".gba"
procedure = [
("apply_bsdiff4", ["base_patch.bsdiff4"]),
("apply_tokens", ["token_data.bin"]),
("enemy_randomize", []),
("hidden_visible", []),
("randomize_sounds", []),
("randomize_music", []),
]
@classmethod
def get_source_data(cls) -> bytes:
return get_base_rom_as_bytes()
def write_tokens(world: "MLSSWorld", patch: MLSSProcedurePatch) -> None:
options_dict = {
"randomize_enemies": world.options.randomize_enemies.value,
"randomize_bosses": world.options.randomize_bosses.value,
"castle_skip": world.options.castle_skip.value,
"randomize_sounds": world.options.randomize_sounds.value,
"music_options": world.options.music_options.value,
"block_visibility": world.options.block_visibility.value,
"seed": world.multiworld.seed,
"player": world.player,
}
patch.write_file("options.json", json.dumps(options_dict).encode("UTF-8"))
# Bake player name into ROM
patch.write_token(APTokenTypes.WRITE, 0xDF0000, world.multiworld.player_name[world.player].encode("UTF-8"))
# Bake seed name into ROM
patch.write_token(APTokenTypes.WRITE, 0xDF00A0, world.multiworld.seed_name.encode("UTF-8"))
# Bake patch into header
patch.write_token(APTokenTypes.WRITE, 0xAD, "P".encode("UTF-8"))
# Intro Skip
patch.write_token(
APTokenTypes.WRITE,
0x244D08,
bytes([0x88, 0x0, 0x19, 0x91, 0x1, 0x20, 0x58, 0x1, 0xF, 0xA0, 0x3, 0x15, 0x27, 0x8]),
)
# Patch S.S Chuckola Loading Zones
patch.write_token(APTokenTypes.WRITE, 0x25FD4E, bytes([0x48, 0x30, 0x80, 0x60, 0x50, 0x2, 0xF]))
patch.write_token(APTokenTypes.WRITE, 0x25FD83, bytes([0x48, 0x30, 0x80, 0x60, 0xC0, 0x2, 0xF]))
patch.write_token(APTokenTypes.WRITE, 0x25FDB8, bytes([0x48, 0x30, 0x05, 0x80, 0xE4, 0x0, 0xF]))
patch.write_token(APTokenTypes.WRITE, 0x25FDED, bytes([0x48, 0x30, 0x06, 0x80, 0xE4, 0x0, 0xF]))
patch.write_token(APTokenTypes.WRITE, 0x25FE22, bytes([0x48, 0x30, 0x07, 0x80, 0xE4, 0x0, 0xF]))
patch.write_token(APTokenTypes.WRITE, 0x25FE57, bytes([0x48, 0x30, 0x08, 0x80, 0xE4, 0x0, 0xF]))
if world.options.extra_pipes:
patch.write_token(APTokenTypes.WRITE, 0xD00001, bytes([0x1]))
if world.options.castle_skip:
patch.write_token(APTokenTypes.WRITE, 0x3AEAB0, bytes([0xC1, 0x67, 0x0, 0x6, 0x1C, 0x08, 0x3]))
patch.write_token(APTokenTypes.WRITE, 0x3AEC18, bytes([0x89, 0x65, 0x0, 0xE, 0xA, 0x08, 0x1]))
if world.options.skip_minecart:
patch.write_token(APTokenTypes.WRITE, 0x3AC728, bytes([0x89, 0x13, 0x0, 0x10, 0xF, 0x08, 0x1]))
patch.write_token(APTokenTypes.WRITE, 0x3AC56C, bytes([0x49, 0x16, 0x0, 0x8, 0x8, 0x08, 0x1]))
if world.options.scale_stats:
patch.write_token(APTokenTypes.WRITE, 0xD00002, bytes([0x1]))
if world.options.xp_multiplier:
patch.write_token(APTokenTypes.WRITE, 0xD00003, bytes([world.options.xp_multiplier.value]))
if world.options.tattle_hp:
patch.write_token(APTokenTypes.WRITE, 0xD00000, bytes([0x1]))
if world.options.music_options == 2:
patch.write_token(APTokenTypes.WRITE, 0x19B118, bytes([0x0, 0x25]))
if world.options.randomize_backgrounds:
all_enemies = Data.enemies + Data.bosses
for address in all_enemies:
patch.write_token(APTokenTypes.WRITE, address + 3, bytes([world.random.randint(0x0, 0x26)]))
for location_name in location_table.keys():
if (
(world.options.skip_minecart and "Minecart" in location_name and "After" not in location_name)
or (world.options.castle_skip and "Bowser" in location_name)
or (world.options.disable_surf and "Surf Minigame" in location_name)
or (world.options.harhalls_pants and "Harhall's" in location_name)
):
continue
if (world.options.chuckle_beans == 0 and "Digspot" in location_name) or (
world.options.chuckle_beans == 1 and location_table[location_name] in hidden
):
continue
if not world.options.coins and "Coin" in location_name:
continue
location = world.multiworld.get_location(location_name, world.player)
item = location.item
address = [address for address in all_locations if address.name == location.name]
item_inject(world, patch, location.address, address[0].itemType, item)
if "Shop" in location_name and "Coffee" not in location_name and item.player != world.player:
desc_inject(world, patch, location, item)
swap_colors(world, patch, world.options.mario_pants.value, 0, True)
swap_colors(world, patch, world.options.luigi_pants.value, 1, True)
swap_colors(world, patch, world.options.mario_color.value, 0)
swap_colors(world, patch, world.options.luigi_color.value, 1)
patch.write_file("token_data.bin", patch.get_token_binary())
def swap_colors(world: "MLSSWorld", patch: MLSSProcedurePatch, color: int, bro: int,
pants_option: Optional[bool] = False):
if not pants_option and color == bro:
return
chaos = False
if not pants_option and color == 11 or color == 12:
chaos = True
if pants_option and color == 11:
chaos = True
for c in [c for c in (cpants[color] if pants_option else colors[color])
if (c[3] == bro if not chaos else c[1] == bro)]:
if chaos:
patch.write_token(APTokenTypes.WRITE, c[0],
bytes([world.random.randint(0, 255), world.random.randint(0, 127)]))
else:
patch.write_token(APTokenTypes.WRITE, c[0], bytes([c[1], c[2]]))
def item_inject(world: "MLSSWorld", patch: MLSSProcedurePatch, location: int, item_type: int, item: Item):
if item.player == world.player:
code = item_table[item.name].itemID
else:
code = 0x3F
if item_type == 0:
patch.write_token(APTokenTypes.WRITE, location, bytes([code]))
elif item_type == 1:
if code == 0x1D or code == 0x1E:
code += 0xE
if 0x20 <= code <= 0x26:
code -= 0x4
insert = int(code)
insert2 = insert % 0x10
insert2 *= 0x10
insert //= 0x10
insert += 0x20
patch.write_token(APTokenTypes.WRITE, location, bytes([insert, insert2]))
elif item_type == 2:
if code == 0x1D or code == 0x1E:
code += 0xE
if 0x20 <= code <= 0x26:
code -= 0x4
patch.write_token(APTokenTypes.WRITE, location, bytes([code]))
elif item_type == 3:
if code == 0x1D or code == 0x1E:
code += 0xE
if code < 0x1D:
code -= 0xA
if 0x20 <= code <= 0x26:
code -= 0xE
patch.write_token(APTokenTypes.WRITE, location, bytes([code]))
else:
patch.write_token(APTokenTypes.WRITE, location, bytes([0x18]))
def desc_inject(world: "MLSSWorld", patch: MLSSProcedurePatch, location: Location, item: Item):
index = -1
for key, value in shop.items():
if location.address in value:
if key == 0x3C05F0:
index = value.index(location.address)
else:
index = value.index(location.address) + 14
for key, value in badge.items():
if index != -1:
break
if location.address in value:
if key == 0x3C0618:
index = value.index(location.address) + 24
else:
index = value.index(location.address) + 41
for key, value in pants.items():
if index != -1:
break
if location.address in value:
if key == 0x3C0618:
index = value.index(location.address) + 48
else:
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"))

571
worlds/mlss/Rules.py Normal file
View File

@ -0,0 +1,571 @@
import typing
from worlds.generic.Rules import add_rule, forbid_item
from .Names.LocationName import LocationName
from .Locations import all_locations, hidden
from . import StateLogic
if typing.TYPE_CHECKING:
from . import MLSSWorld
def set_rules(world: "MLSSWorld", excluded):
for location in all_locations:
if "Digspot" in location.name:
if (world.options.skip_minecart and "Minecart" in location.name) or (
world.options.castle_skip and "Bowser" in location.name
):
continue
if world.options.chuckle_beans == 0 or world.options.chuckle_beans == 1 and location.id in hidden:
continue
add_rule(
world.get_location(location.name),
lambda state: StateLogic.canDig(state, world.player),
)
if "Beanstone" in location.name:
add_rule(
world.get_location(location.name),
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),
)
if location.itemType != 0 and location.name not in excluded:
if "Bowser" in location.name and world.options.castle_skip:
continue
forbid_item(world.get_location(location.name), "5 Coins", world.player)
if world.options.chuckle_beans == 2:
add_rule(
world.get_location(LocationName.HoohooVillageSuperHammerCaveDigspot),
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsFarmRoomDigspot2),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsFarmRoomDigspot3),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsWhiteFruitRoomDigspot3),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.JokesEndJojoraRoomDigspot),
lambda state: StateLogic.canDash(state, world.player),
)
if world.options.chuckle_beans != 0:
add_rule(
world.get_location(LocationName.HoohooMountainBaseBoostatueRoomDigspot2),
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsFarmRoomDigspot1),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsWhiteFruitRoomDigspot2),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.TeeheeValleyPastUltraHammersDigspot1),
lambda state: StateLogic.ultra(state, world.player),
)
add_rule(
world.get_location(LocationName.TeeheeValleyPastUltraHammersDigspot3),
lambda state: StateLogic.ultra(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsNorthBeachDigspot3),
lambda state: StateLogic.canDash(state, world.player) or StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsEDigspot2),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsNEDigspot1),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSRoom1Digspot2),
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
add_rule(
world.get_location(LocationName.HoohooVillageHammerHouseBlock),
lambda state: StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.HoohooMountainBaseBoostatueRoomBlock2),
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsBooStatueMole),
lambda state: StateLogic.canMini(state, world.player) and StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.HoohooVillageSuperHammerCaveBlock),
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsFarmRoomMoleReward1),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsFarmRoomMoleReward2),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsThunderHandMole),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsNWBlock),
lambda state: StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsBeanFruit1),
lambda state: StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsBeanFruit2),
lambda state: StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsBeanFruit3),
lambda state: StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsBeanFruit4),
lambda state: StateLogic.super(state, world.player) and StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsBeanFruit5),
lambda state: StateLogic.super(state, world.player) and StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsBeanFruit6),
lambda state: StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsBeanFruit7),
lambda state: StateLogic.teehee(state, world.player) and StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSRoom1Block),
lambda state: StateLogic.ultra(state, world.player) and StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSRoom2Block1),
lambda state: StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.WoohooHooniversityMiniMarioPuzzleSecretAreaBlock1),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.WoohooHooniversityMiniMarioPuzzleSecretAreaBlock2),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.WoohooHooniversityMiniMarioPuzzleSecretAreaBlock3),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.WoohooHooniversityMiniMarioPuzzleSecretAreaBlock4),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.WoohooHooniversityMiniMarioPuzzleBlock),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSecretScroll1),
lambda state: StateLogic.thunder(state, world.player) and StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSecretScroll2),
lambda state: StateLogic.thunder(state, world.player) and StateLogic.ultra(state, world.player),
)
add_rule(
world.get_location(LocationName.HoohooVillageMoleBehindTurtle),
lambda state: StateLogic.canDash(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsNESoloMarioMole1),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsNESoloMarioMole2),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSuperHammerUpgrade),
lambda state: StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsUltraHammerUpgrade),
lambda state: StateLogic.thunder(state, world.player)
and StateLogic.pieces(state, world.player)
and StateLogic.castleTown(state, world.player)
and StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSoloLuigiCaveMole),
lambda state: StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsRedChuckolaFruit),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsWhiteChuckolaFruit),
lambda state: StateLogic.canDig(state, world.player) and StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsAfterChucklerootBlock1),
lambda state: StateLogic.fruits(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsAfterChucklerootBlock2),
lambda state: StateLogic.fruits(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsAfterChucklerootBlock3),
lambda state: StateLogic.fruits(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsAfterChucklerootBlock4),
lambda state: StateLogic.fruits(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsAfterChucklerootBlock5),
lambda state: StateLogic.fruits(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsAfterChucklerootBlock6),
lambda state: StateLogic.fruits(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsRoom7Block1),
lambda state: StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsRoom7Block2),
lambda state: StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsRoom4Block1),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsRoom4Block2),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsRoom4Block3),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsPipeRoomBlock1),
lambda state: StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsPipeRoomBlock2),
lambda state: StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanCastleTownMiniMarioBlock1),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanCastleTownMiniMarioBlock2),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanCastleTownMiniMarioBlock3),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanCastleTownMiniMarioBlock4),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanCastleTownMiniMarioBlock5),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanCastleFakeBeastar),
lambda state: StateLogic.pieces(state, world.player) and StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanCastlePeachsExtraDress),
lambda state: StateLogic.pieces(state, world.player) and StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.SewersRoom5Block1),
lambda state: StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.SewersRoom5Block2),
lambda state: StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.GwarharLagoonFirstUnderwaterAreaRoom1Block),
lambda state: StateLogic.canDash(state, world.player),
)
add_rule(
world.get_location(LocationName.GwarharLagoonFirstUnderwaterAreaRoom2Block1),
lambda state: StateLogic.canDash(state, world.player),
)
add_rule(
world.get_location(LocationName.GwarharLagoonFirstUnderwaterAreaRoom2Block2),
lambda state: StateLogic.canDash(state, world.player),
)
add_rule(
world.get_location(LocationName.GwarharLagoonRedPearlBean),
lambda state: StateLogic.fire(state, world.player) and StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.GwarharLagoonGreenPearlBean),
lambda state: StateLogic.fire(state, world.player) and StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.TeeheeValleyPastUltraHammersBlock1),
lambda state: StateLogic.ultra(state, world.player),
)
add_rule(
world.get_location(LocationName.TeeheeValleyPastUltraHammersBlock2),
lambda state: StateLogic.ultra(state, world.player),
)
add_rule(
world.get_location(LocationName.TeeheeValleySoloLuigiMazeRoom1Block),
lambda state: StateLogic.ultra(state, world.player),
)
add_rule(
world.get_location(LocationName.OhoOasisFirebrand),
lambda state: StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.OhoOasisThunderhand),
lambda state: StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanstarPieceYoshiTheater),
lambda state: StateLogic.neon(state, world.player),
)
add_rule(
world.get_location(LocationName.YoshiTheaterAzureYoshi),
lambda state: StateLogic.beanFruit(state, world.player),
)
add_rule(
world.get_location(LocationName.YoshiTheaterBlueYoshi),
lambda state: StateLogic.beanFruit(state, world.player),
)
add_rule(
world.get_location(LocationName.YoshiTheaterGreenYoshi),
lambda state: StateLogic.beanFruit(state, world.player),
)
add_rule(
world.get_location(LocationName.YoshiTheaterOrangeYoshi),
lambda state: StateLogic.beanFruit(state, world.player),
)
add_rule(
world.get_location(LocationName.YoshiTheaterPurpleYoshi),
lambda state: StateLogic.beanFruit(state, world.player),
)
add_rule(
world.get_location(LocationName.YoshiTheaterRedYoshi),
lambda state: StateLogic.beanFruit(state, world.player),
)
add_rule(
world.get_location(LocationName.YoshiTheaterYellowYoshi),
lambda state: StateLogic.beanFruit(state, world.player),
)
add_rule(
world.get_location(LocationName.WinkleAreaBeanstarRoomBlock),
lambda state: StateLogic.winkle(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanstarPieceWinkleArea),
lambda state: StateLogic.winkle(state, world.player),
)
add_rule(
world.get_location(LocationName.GwarharLagoonSpangleReward),
lambda state: StateLogic.spangle(state, world.player),
)
add_rule(
world.get_location(LocationName.PantsShopMomPiranhaFlag1),
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.PantsShopMomPiranhaFlag2),
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.PantsShopMomPiranhaFlag3),
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.BadgeShopMomPiranhaFlag1),
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.BadgeShopMomPiranhaFlag2),
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.BadgeShopMomPiranhaFlag3),
lambda state: StateLogic.brooch(state, world.player) or StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.ChateauGreenGoblet),
lambda state: StateLogic.brooch(state, world.player) and StateLogic.canDig(state, world.player),
)
add_rule(
world.get_location(LocationName.ChateauRedGoblet),
lambda state: StateLogic.brooch(state, world.player) and StateLogic.canMini(state, world.player),
)
add_rule(
world.get_location(LocationName.GwarharLagoonSpangle),
lambda state: StateLogic.ultra(state, world.player),
)
add_rule(
world.get_location(LocationName.GwarharLagoonSpangleRoomBlock),
lambda state: StateLogic.ultra(state, world.player),
)
if world.options.difficult_logic:
add_rule(
world.get_location(LocationName.GwarharLagoonSpangleReward),
lambda state: StateLogic.canCrash(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanstarPieceHermie),
lambda state: StateLogic.canCrash(state, world.player),
)
if world.options.chuckle_beans != 0:
add_rule(
world.get_location(LocationName.GwarharLagoonPastHermieDigspot),
lambda state: StateLogic.canCrash(state, world.player),
)
if world.options.coins:
add_rule(
world.get_location(LocationName.HoohooMountainBaseBooStatueCaveCoinBlock1),
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.HoohooMountainBaseBooStatueCaveCoinBlock2),
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.HoohooMountainBaseBooStatueCaveCoinBlock3),
lambda state: StateLogic.canCrash(state, world.player) or StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsNWCoinBlock),
lambda state: StateLogic.super(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSRoom1CoinBlock),
lambda state: StateLogic.ultra(state, world.player) and StateLogic.thunder(state, world.player),
)
add_rule(
world.get_location(LocationName.BeanbeanOutskirtsSRoom2CoinBlock),
lambda state: StateLogic.canCrash(state, world.player),
)
add_rule(
world.get_location(LocationName.ChateauPoppleRoomCoinBlock1),
lambda state: StateLogic.brooch(state, world.player),
)
add_rule(
world.get_location(LocationName.ChateauPoppleRoomCoinBlock2),
lambda state: StateLogic.brooch(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsCaveRoom1CoinBlock),
lambda state: StateLogic.brooch(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsCaveRoom2CoinBlock),
lambda state: StateLogic.brooch(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsCaveRoom3CoinBlock),
lambda state: StateLogic.brooch(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsPipe5RoomCoinBlock),
lambda state: StateLogic.brooch(state, world.player) and StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsRoom7CoinBlock),
lambda state: StateLogic.brooch(state, world.player) and StateLogic.hammers(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsAfterChucklerootCoinBlock),
lambda state: StateLogic.brooch(state, world.player) and StateLogic.fruits(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsKoopaRoomCoinBlock),
lambda state: StateLogic.brooch(state, world.player),
)
add_rule(
world.get_location(LocationName.ChucklehuckWoodsWinkleAreaCaveCoinBlock),
lambda state: StateLogic.brooch(state, world.player) and StateLogic.canDash(state, world.player),
)
add_rule(
world.get_location(LocationName.SewersPrisonRoomCoinBlock),
lambda state: StateLogic.rose(state, world.player),
)
add_rule(
world.get_location(LocationName.TeeheeValleyPastUltraHammerRocksCoinBlock),
lambda state: StateLogic.ultra(state, world.player),
)
add_rule(
world.get_location(LocationName.SSChuckolaStorageRoomCoinBlock1),
lambda state: StateLogic.super(state, world.player) or StateLogic.canDash(state, world.player),
)
add_rule(
world.get_location(LocationName.SSChuckolaStorageRoomCoinBlock2),
lambda state: StateLogic.super(state, world.player) or StateLogic.canDash(state, world.player),
)
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)),
)
add_rule(
world.get_location(LocationName.JokesEndSecondFloorWestRoomCoinBlock),
lambda state: StateLogic.ultra(state, world.player)
and StateLogic.fire(state, world.player)
and (
StateLogic.membership(state, world.player)
or (StateLogic.canDig(state, world.player) and StateLogic.canMini(state, world.player))
),
)
add_rule(
world.get_location(LocationName.JokesEndNorthofBridgeRoomCoinBlock),
lambda state: StateLogic.ultra(state, world.player)
and StateLogic.fire(state, world.player)
and StateLogic.canDig(state, world.player)
and (StateLogic.membership(state, world.player) or StateLogic.canMini(state, world.player)),
)
if not world.options.difficult_logic:
add_rule(
world.get_location(LocationName.JokesEndNorthofBridgeRoomCoinBlock),
lambda state: StateLogic.canCrash(state, world.player),
)

155
worlds/mlss/StateLogic.py Normal file
View File

@ -0,0 +1,155 @@
def canDig(state, player):
return state.has("Green Goblet", player) and state.has("Hammers", player)
def canMini(state, player):
return state.has("Red Goblet", player) and state.has("Hammers", player)
def canDash(state, player):
return state.has("Red Pearl Bean", player) and state.has("Firebrand", player)
def canCrash(state, player):
return state.has("Green Pearl Bean", player) and state.has("Thunderhand", player)
def hammers(state, player):
return state.has("Hammers", player)
def super(state, player):
return state.has("Hammers", player, 2)
def ultra(state, player):
return state.has("Hammers", player, 3)
def fruits(state, player):
return (
state.has("Red Chuckola Fruit", player)
and state.has("Purple Chuckola Fruit", player)
and state.has("White Chuckola Fruit", player)
)
def pieces(state, player):
return (
state.has("Beanstar Piece 1", player)
and state.has("Beanstar Piece 2", player)
and state.has("Beanstar Piece 3", player)
and state.has("Beanstar Piece 4", player)
)
def neon(state, player):
return (
state.has("Blue Neon Egg", player)
and state.has("Red Neon Egg", player)
and state.has("Green Neon Egg", player)
and state.has("Yellow Neon Egg", player)
and state.has("Purple Neon Egg", player)
and state.has("Orange Neon Egg", player)
and state.has("Azure Neon Egg", player)
)
def spangle(state, player):
return state.has("Spangle", player)
def rose(state, player):
return state.has("Peasley's Rose", player)
def brooch(state, player):
return state.has("Beanbean Brooch", player)
def thunder(state, player):
return state.has("Thunderhand", player)
def fire(state, player):
return state.has("Firebrand", player)
def dressBeanstar(state, player):
return state.has("Peach's Extra Dress", player) and state.has("Fake Beanstar", player)
def membership(state, player):
return state.has("Membership Card", player)
def winkle(state, player):
return state.has("Winkle Card", player)
def beanFruit(state, player):
return (
state.has("Bean Fruit 1", player)
and state.has("Bean Fruit 2", player)
and state.has("Bean Fruit 3", player)
and state.has("Bean Fruit 4", player)
and state.has("Bean Fruit 5", player)
and state.has("Bean Fruit 6", player)
and state.has("Bean Fruit 7", player)
)
def surfable(state, player):
return ultra(state, player) and (
(canDig(state, player) and canMini(state, player)) or (membership(state, player) and fire(state, player))
)
def postJokes(state, player):
return (
surfable(state, player)
and canDig(state, player)
and dressBeanstar(state, player)
and pieces(state, player)
and fruits(state, player)
and brooch(state, player)
and rose(state, player)
and canDash(state, player)
)
def teehee(state, player):
return super(state, player) or canDash(state, player)
def castleTown(state, player):
return fruits(state, player) and brooch(state, player)
def fungitown(state, player):
return (
castleTown(state, player)
and thunder(state, player)
and rose(state, player)
and (super(state, player) or canDash(state, player))
)
def piranha_shop(state, player):
return state.can_reach("Shop Mom Piranha Flag", "Region", player)
def fungitown_shop(state, player):
return state.can_reach("Shop Enter Fungitown Flag", "Region", player)
def star_shop(state, player):
return state.can_reach("Shop Beanstar Complete Flag", "Region", player)
def birdo_shop(state, player):
return state.can_reach("Shop Birdo Flag", "Region", player)
def fungitown_birdo_shop(state, player):
return state.can_reach("Fungitown Shop Birdo Flag", "Region", player)

183
worlds/mlss/__init__.py Normal file
View File

@ -0,0 +1,183 @@
import os
import pkgutil
import typing
import settings
from BaseClasses import Tutorial, ItemClassification
from worlds.AutoWorld import WebWorld, World
from typing import List, 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 .Names.LocationName import LocationName
from .Client import MLSSClient
from .Regions import create_regions, connect_regions
from .Rom import MLSSProcedurePatch, write_tokens
from .Rules import set_rules
class MLSSWebWorld(WebWorld):
theme = "partyTime"
bug_report_page = "https://github.com/jamesbrq/ArchipelagoMLSS/issues"
tutorials = [
Tutorial(
tutorial_name="Setup Guide",
description="A guide to setting up Mario & Luigi: Superstar Saga for Archipelago.",
language="English",
file_name="setup_en.md",
link="setup/en",
authors=["jamesbrq"],
)
]
class MLSSSettings(settings.Group):
class RomFile(settings.UserFilePath):
"""File name of the MLSS US rom"""
copy_to = "Mario & Luigi - Superstar Saga (U).gba"
description = "MLSS ROM File"
md5s = ["4b1a5897d89d9e74ec7f630eefdfd435"]
rom_file: RomFile = RomFile(RomFile.copy_to)
rom_start: bool = True
class MLSSWorld(World):
"""
Adventure with Mario and Luigi together in the Beanbean Kingdom
to stop the evil Cackletta and retrieve the Beanstar.
"""
game = "Mario & Luigi Superstar Saga"
web = MLSSWebWorld()
options_dataclass = MLSSOptions
options: MLSSOptions
settings: typing.ClassVar[MLSSSettings]
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, 4, 5)
disabled_locations: List[str]
def generate_early(self) -> None:
self.disabled_locations = []
if self.options.chuckle_beans == 0:
self.disabled_locations += [location.name for location in all_locations if "Digspot" in location.name]
if self.options.castle_skip:
self.disabled_locations += [location.name for location in all_locations if "Bowser" in location.name]
if self.options.chuckle_beans == 1:
self.disabled_locations = [location.name for location in all_locations if location.id in hidden]
if self.options.skip_minecart:
self.disabled_locations += [LocationName.HoohooMountainBaseMinecartCaveDigspot]
if self.options.disable_surf:
self.disabled_locations += [LocationName.SurfMinigame]
if self.options.harhalls_pants:
self.disabled_locations += [LocationName.HarhallsPants]
if not self.options.coins:
self.disabled_locations += [location.name for location in all_locations if location in coins]
def create_regions(self) -> None:
create_regions(self, self.disabled_locations)
connect_regions(self)
item = self.create_item("Mushroom")
self.get_location(LocationName.ShopStartingFlag1).place_locked_item(item)
item = self.create_item("Syrup")
self.get_location(LocationName.ShopStartingFlag2).place_locked_item(item)
item = self.create_item("1-UP Mushroom")
self.get_location(LocationName.ShopStartingFlag3).place_locked_item(item)
item = self.create_item("Hoo Bean")
self.get_location(LocationName.PantsShopStartingFlag1).place_locked_item(item)
item = self.create_item("Chuckle Bean")
self.get_location(LocationName.PantsShopStartingFlag2).place_locked_item(item)
def fill_slot_data(self) -> Dict[str, Any]:
return {
"CastleSkip": self.options.castle_skip.value,
"SkipMinecart": self.options.skip_minecart.value,
"DisableSurf": self.options.disable_surf.value,
"HarhallsPants": self.options.harhalls_pants.value,
"ChuckleBeans": self.options.chuckle_beans.value,
"DifficultLogic": self.options.difficult_logic.value,
"Coins": self.options.coins.value,
}
def create_items(self) -> None:
# First add in all progression and useful items
required_items = []
precollected = [item for item in itemList if item in self.multiworld.precollected_items]
for item in itemList:
if item.classification != ItemClassification.filler and item.classification != ItemClassification.skip_balancing:
freq = item_frequencies.get(item.itemName, 1)
if item in precollected:
freq = max(freq - precollected.count(item), 0)
if self.options.harhalls_pants and "Harhall's" in item.itemName:
continue
required_items += [item.itemName for _ in range(freq)]
for itemName in required_items:
self.multiworld.itempool.append(self.create_item(itemName))
# Then, create our list of filler items
filler_items = []
for item in itemList:
if item.classification != ItemClassification.filler:
continue
if item.itemName == "5 Coins" and not self.options.coins:
continue
freq = item_frequencies.get(item.itemName, 1)
if self.options.chuckle_beans == 0:
if item.itemName == "Chuckle Bean":
continue
if self.options.chuckle_beans == 1:
if item.itemName == "Chuckle Bean":
freq -= 59
filler_items += [item.itemName for _ in range(freq)]
# 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) - 5
if self.options.castle_skip:
remaining -= len(bowsers) + len(bowsersMini) - (5 if self.options.chuckle_beans == 0 else 0)
if self.options.skip_minecart and self.options.chuckle_beans == 2:
remaining -= 1
if self.options.disable_surf:
remaining -= 1
if self.options.harhalls_pants:
remaining -= 1
if self.options.chuckle_beans == 0:
remaining -= 192
if self.options.chuckle_beans == 1:
remaining -= 59
if not self.options.coins:
remaining -= len(coins)
self.multiworld.itempool += [
self.create_item(filler_item_name) for filler_item_name in self.random.sample(filler_items, remaining)
]
def set_rules(self) -> None:
set_rules(self, self.disabled_locations)
if self.options.castle_skip:
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach(
"PostJokes", "Region", self.player
)
else:
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach(
"Bowser's Castle Mini", "Region", self.player
)
def create_item(self, name: str) -> MLSSItem:
item = item_table[name]
return MLSSItem(item.itemName, item.classification, item.code, self.player)
def get_filler_item_name(self) -> str:
return self.random.choice(list(filter(lambda item: item.classification == ItemClassification.filler, itemList)))
def generate_output(self, output_directory: str) -> None:
patch = MLSSProcedurePatch(player=self.player, player_name=self.multiworld.player_name[self.player])
patch.write_file("base_patch.bsdiff4", pkgutil.get_data(__name__, "data/basepatch.bsdiff"))
write_tokens(self, patch)
rom_path = os.path.join(
output_directory, f"{self.multiworld.get_out_file_name_base(self.player)}" f"{patch.patch_file_ending}"
)
patch.write(rom_path)

Binary file not shown.

View File

@ -0,0 +1,66 @@
# Mario & Luigi: Superstar Saga
## Where is the options page?
The [player options page for this game](../player-options) contains all the options you need to configure and
export a config file.
## What does randomization do to this game?
Items which the player would normally acquire throughout the game have been moved around. Logic remains, so the game is
always able to be completed, but because of the item shuffle, the player may need to access certain areas before they
would in the vanilla game.
The game has been changed to an open-world style as opposed to the linear style the vanilla game has.
Other Features such as Turbo through textboxes (Hold L/R+A) and Pipe Warping from any room (Hold L+R+SELECT) have been added for convenience.
Enemies and Bosses can be randomized, and their stats can be scaled to feel more like the vanilla game's stats.
Other aspects of the game can be randomized as well such as music, sounds, battle backgrounds, Mario and Luigi's Colors, and more.
## What is the goal of Mario & Luigi: Superstar Saga when randomized?
Defeat Cackletta's Soul in Bowser's Castle. This requires you to collect all 4 Beanstar Pieces, restore the Beanstar, and bring Peach's Extra Dress and the Fake Beanstar to Fawful at the end of Jokes End.
In total, this requires:
- 4 Beanstar Pieces
- Peach's Extra Dress
- Fake Beanstar
- Ultra Hammers
- Fire Hand
- Thunder Hand
- Red Pearl Bean
- Green Pearl Bean
- Green Goblet
- Peasley's Rose
- Beanbean Brooch
- All 3 Chuckola Fruits
- Membership Card OR Red Goblet
## What items and locations can get shuffled?
Locations in which items can be found:
- All Item Blocks and Coin Blocks
- All Chuckle Bean Digspots
- All Shop items
- All Pants and Badge shop items
- All Espresso brews and rewards
- All Minigame Rewards
- All Event based items
Items that can be shuffled:
- All consumable items (Mushrooms, Nuts, Syrups etc.)
- All Hoo Beans and Chuckle Beans
- All Badges and Pants
- All key items (Beanfruits, Beanbean Brooch, Hammers etc.)
- All Extra Gears (Great Force, Gameboy Horror SP etc.)
## What does another world's item look like in Mario & Luigi: Superstar Saga?
Items will show up as a Golden Mushroom from boxes and Digspots and "AP Item" in all textboxes.
Items in a shop from another player's world will display the player name and item name in addition to being displayed as an AP Item.
## When the player receives an item, what happens?
Items will be placed directly into the players inventory after a few seconds. Sometimes for certain events and cutscenes to be properly triggered right after you received an item, you may have to leave and re-enter the room to properly load everything required for the respective event or cutscene.

View File

@ -0,0 +1,53 @@
# Setup Guide for Mario & Luigi: Superstar Saga Archipelago
## Important
As we are using Bizhawk, this guide is only applicable to Windows and Linux systems.
## Required Software
- Bizhawk: [Bizhawk Releases from TASVideos](https://tasvideos.org/BizHawk/ReleaseHistory)
- Version 2.9.1 is recommended.
- Detailed installation instructions for Bizhawk can be found at the above link.
- Windows users must run the prerequisite installer first, which can also be found at the above link.
- The built-in Bizhawk client, which can be installed [here](https://github.com/ArchipelagoMW/Archipelago/releases)
- A US copy of Mario & Luigi: Superstar Saga
## Optional Software
- [Poptracker](https://github.com/black-sliver/PopTracker/releases)
- [MLSS Autotracker](https://github.com/seto10987/MLSS-PopTracker/releases)
## Configuring your YAML file
### What is a YAML file and why do I need one?
Your YAML file contains a set of configuration options which provide the generator with information about how it should
generate your game. Each player of a multiworld will provide their own YAML file. This setup allows each player to enjoy
an experience customized for their taste, and different players in the same multiworld can all have different options.
### Where do I get a YAML file?
You can customize your options by visiting the
[Mario & Luigi Superstar Saga Options Page](/games/Mario%20&%20Luigi%20Superstar%20Saga/player-options)
## Joining a MultiWorld Game
### Obtain your GBA patch file
When you join a multiworld game, you will be asked to provide your YAML file to whoever is hosting. Once that is done,
the host will provide you with either a link to download your data file, or with a zip file containing everyone's data
files. Your data file should have a `.apmlss` extension.
Double-click on your `.apmlss` file to start your client and start the ROM patch process. Once the process is finished, the client and the emulator will be started automatically (if you associated the extension
to the emulator as recommended).
### Connect to the Multiserver
Once both the client and the emulator are started, you must connect them. Within the emulator click on the "Tools"
menu and select "Lua Console". Click the folder button or press Ctrl+O to open a Lua script.
Navigate to your Archipelago install folder and open `data/lua/connector_bizhawk_generic.lua`.
To connect the client to the multiserver simply put `<address>:<port>` on the textfield on top and press enter (if the
server uses password, type in the bottom textfield `/connect <address>:<port> [password]`)