Super Mario Land 2: Implement New Game (#2730)

Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com>
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
Co-authored-by: alchav <alchav@jalchavware.com>
This commit is contained in:
Alchav
2025-05-21 11:02:30 -04:00
committed by GitHub
parent d5bacaba63
commit 955a86803f
16 changed files with 3578 additions and 0 deletions

View File

@@ -81,6 +81,7 @@ Currently, the following games are supported:
* Civilization VI * Civilization VI
* The Legend of Zelda: The Wind Waker * The Legend of Zelda: The Wind Waker
* Jak and Daxter: The Precursor Legacy * Jak and Daxter: The Precursor Legacy
* Super Mario Land 2: 6 Golden Coins
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/). 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 Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled

View File

@@ -178,6 +178,9 @@
# Super Mario 64 # Super Mario 64
/worlds/sm64ex/ @N00byKing /worlds/sm64ex/ @N00byKing
# Super Mario Land 2: 6 Golden Coins
/worlds/marioland2/ @Alchav
# Super Mario World # Super Mario World
/worlds/smw/ @PoryGone /worlds/smw/ @PoryGone

21
worlds/marioland2/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022-2023 Alex "Alchav" Avery
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,449 @@
import base64
import Utils
import settings
from copy import deepcopy
from worlds.AutoWorld import World, WebWorld
from BaseClasses import Region, Location, Item, ItemClassification, Tutorial
from . import client
from .rom import generate_output, SuperMarioLand2ProcedurePatch
from .options import SML2Options
from .locations import (locations, location_name_to_id, level_name_to_id, level_id_to_name, START_IDS, coins_coords,
auto_scroll_max)
from .items import items
from .sprites import level_sprites
from .sprite_randomizer import randomize_enemies, randomize_platforms
from .logic import has_pipe_up, has_pipe_down, has_pipe_left, has_pipe_right, has_level_progression, is_auto_scroll
from . import logic
class MarioLand2Settings(settings.Group):
class SML2RomFile(settings.UserFilePath):
"""File name of the Super Mario Land 2 1.0 ROM"""
description = "Super Mario Land 2 - 6 Golden Coins (USA, Europe) 1.0 ROM File"
copy_to = "Super Mario Land 2 - 6 Golden Coins (USA, Europe).gb"
md5s = [SuperMarioLand2ProcedurePatch.hash]
rom_file: SML2RomFile = SML2RomFile(SML2RomFile.copy_to)
class MarioLand2WebWorld(WebWorld):
setup_en = Tutorial(
"Multiworld Setup Guide",
"A guide to playing Super Mario Land 2 with Archipelago.",
"English",
"setup_en.md",
"setup/en",
["Alchav"]
)
tutorials = [setup_en]
class MarioLand2World(World):
"""Super Mario Land 2 is a classic platformer that follows Mario on a quest to reclaim his castle from the
villainous Wario. This iconic game features 32 levels, unique power-ups, and introduces Wario as Mario's
arch-rival.""" # -ChatGPT
game = "Super Mario Land 2"
settings_key = "sml2_options"
settings: MarioLand2Settings
location_name_to_id = location_name_to_id
item_name_to_id = {item_name: ID for ID, item_name in enumerate(items, START_IDS)}
web = MarioLand2WebWorld()
item_name_groups = {
"Level Progression": {
item_name for item_name in items if item_name.endswith(("Progression", "Secret", "Secret 1", "Secret 2"))
and "Auto Scroll" not in item_name
},
"Bells": {item_name for item_name in items if "Bell" in item_name},
"Golden Coins": {"Mario Coin", "Macro Coin", "Space Coin", "Tree Coin", "Turtle Coin", "Pumpkin Coin"},
"Coins": {"1 Coin", *{f"{i} Coins" for i in range(2, 169)}},
"Powerups": {"Mushroom", "Fire Flower", "Carrot"},
"Difficulties": {"Easy Mode", "Normal Mode"},
"Auto Scroll Traps": {item_name for item_name in items
if "Auto Scroll" in item_name and "Cancel" not in item_name},
"Cancel Auto Scrolls": {item_name for item_name in items if "Cancel Auto Scroll" in item_name},
}
location_name_groups = {
"Bosses": {
"Tree Zone 5 - Boss", "Space Zone 2 - Boss", "Macro Zone 4 - Boss",
"Pumpkin Zone 4 - Boss", "Mario Zone 4 - Boss", "Turtle Zone 3 - Boss"
},
"Normal Exits": {location for location in locations if locations[location]["type"] == "level"},
"Secret Exits": {location for location in locations if locations[location]["type"] == "secret"},
"Bells": {location for location in locations if locations[location]["type"] == "bell"},
"Coins": {location for location in location_name_to_id if "Coin" in location}
}
options_dataclass = SML2Options
options: SML2Options
generate_output = generate_output
def __init__(self, world, player: int):
super().__init__(world, player)
self.auto_scroll_levels = []
self.num_coin_locations = []
self.max_coin_locations = {}
self.sprite_data = {}
self.coin_fragments_required = 0
def generate_early(self):
self.sprite_data = deepcopy(level_sprites)
if self.options.randomize_enemies:
randomize_enemies(self.sprite_data, self.random)
if self.options.randomize_platforms:
randomize_platforms(self.sprite_data, self.random)
if self.options.marios_castle_midway_bell:
self.sprite_data["Mario's Castle"][35]["sprite"] = "Midway Bell"
if self.options.auto_scroll_chances == "vanilla":
self.auto_scroll_levels = [int(i in [19, 25, 30]) for i in range(32)]
else:
self.auto_scroll_levels = [int(self.random.randint(1, 100) <= self.options.auto_scroll_chances)
for _ in range(32)]
self.auto_scroll_levels[level_name_to_id["Mario's Castle"]] = 0
unbeatable_scroll_levels = ["Tree Zone 3", "Macro Zone 2", "Space Zone 1", "Turtle Zone 2", "Pumpkin Zone 2"]
if not self.options.shuffle_midway_bells:
unbeatable_scroll_levels.append("Pumpkin Zone 1")
for level, i in enumerate(self.auto_scroll_levels):
if i == 1:
if self.options.auto_scroll_mode in ("global_cancel_item", "level_cancel_items"):
self.auto_scroll_levels[level] = 2
elif self.options.auto_scroll_mode == "chaos":
if (self.options.accessibility == "full"
and level_id_to_name[level] in unbeatable_scroll_levels):
self.auto_scroll_levels[level] = 2
else:
self.auto_scroll_levels[level] = self.random.randint(1, 3)
elif (self.options.accessibility == "full"
and level_id_to_name[level] in unbeatable_scroll_levels):
self.auto_scroll_levels[level] = 0
if self.auto_scroll_levels[level] == 1 and "trap" in self.options.auto_scroll_mode.current_key:
self.auto_scroll_levels[level] = 3
def create_regions(self):
menu_region = Region("Menu", self.player, self.multiworld)
self.multiworld.regions.append(menu_region)
created_regions = []
for location_name, data in locations.items():
region_name = location_name.split(" -")[0]
if region_name in created_regions:
region = self.multiworld.get_region(region_name, self.player)
else:
region = Region(region_name, self.player, self.multiworld)
if region_name == "Tree Zone Secret Course":
region_to_connect = self.multiworld.get_region("Tree Zone 2", self.player)
elif region_name == "Space Zone Secret Course":
region_to_connect = self.multiworld.get_region("Space Zone 1", self.player)
elif region_name == "Macro Zone Secret Course":
region_to_connect = self.multiworld.get_region("Macro Zone 1", self.player)
elif region_name == "Pumpkin Zone Secret Course 1":
region_to_connect = self.multiworld.get_region("Pumpkin Zone 2", self.player)
elif region_name == "Pumpkin Zone Secret Course 2":
region_to_connect = self.multiworld.get_region("Pumpkin Zone 3", self.player)
elif region_name == "Turtle Zone Secret Course":
region_to_connect = self.multiworld.get_region("Turtle Zone 2", self.player)
elif region_name.split(" ")[-1].isdigit() and int(region_name.split(" ")[-1]) > 1:
region_to_connect = self.multiworld.get_region(" ".join(region_name.split(" ")[:2])
+ f" {int(region_name.split(' ')[2]) - 1}",
self.player)
else:
region_to_connect = menu_region
region_to_connect.connect(region)
self.multiworld.regions.append(region)
created_regions.append(region_name)
if location_name == "Mario's Castle - Midway Bell" and not self.options.marios_castle_midway_bell:
continue
region.locations.append(MarioLand2Location(self.player, location_name,
self.location_name_to_id[location_name], region))
self.multiworld.get_region("Macro Zone Secret Course", self.player).connect(
self.multiworld.get_region("Macro Zone 4", self.player))
self.multiworld.get_region("Macro Zone 4", self.player).connect(
self.multiworld.get_region("Macro Zone Secret Course", self.player))
castle = self.multiworld.get_region("Mario's Castle", self.player)
wario = MarioLand2Location(self.player, "Mario's Castle - Wario", parent=castle)
castle.locations.append(wario)
wario.place_locked_item(MarioLand2Item("Wario Defeated", ItemClassification.progression, None, self.player))
if self.options.coinsanity:
coinsanity_checks = self.options.coinsanity_checks.value
self.num_coin_locations = [[region, 1] for region in created_regions if region != "Mario's Castle"]
self.max_coin_locations = {region: len(coins_coords[region]) for region in created_regions
if region != "Mario's Castle"}
if self.options.accessibility == "full" or self.options.auto_scroll_mode == "always":
for level in self.max_coin_locations:
if level in auto_scroll_max and self.auto_scroll_levels[level_name_to_id[level]] in (1, 3):
if isinstance(auto_scroll_max[level], tuple):
self.max_coin_locations[level] = min(
auto_scroll_max[level][int(self.options.shuffle_midway_bells.value)],
self.max_coin_locations[level])
else:
self.max_coin_locations[level] = min(auto_scroll_max[level], self.max_coin_locations[level])
coinsanity_checks = min(sum(self.max_coin_locations.values()), coinsanity_checks)
for i in range(coinsanity_checks - 31):
self.num_coin_locations.sort(key=lambda region: self.max_coin_locations[region[0]] / region[1])
self.num_coin_locations[-1][1] += 1
coin_locations = []
for level, coins in self.num_coin_locations:
if self.max_coin_locations[level]:
coin_thresholds = self.random.sample(range(1, self.max_coin_locations[level] + 1), coins)
coin_locations += [f"{level} - {i} Coin{'s' if i > 1 else ''}" for i in coin_thresholds]
for location_name in coin_locations:
region = self.multiworld.get_region(location_name.split(" -")[0], self.player)
region.locations.append(MarioLand2Location(self.player, location_name,
self.location_name_to_id[location_name], parent=region))
def set_rules(self):
entrance_rules = {
"Menu -> Space Zone 1": lambda state: state.has("Hippo Bubble", self.player)
or (state.has("Carrot", self.player)
and not is_auto_scroll(state, self.player, "Hippo Zone")),
"Space Zone 1 -> Space Zone Secret Course": lambda state: state.has("Space Zone Secret", self.player),
"Space Zone 1 -> Space Zone 2": lambda state: has_level_progression(state, "Space Zone Progression", self.player),
"Tree Zone 1 -> Tree Zone 2": lambda state: has_level_progression(state, "Tree Zone Progression", self.player),
"Tree Zone 2 -> Tree Zone Secret Course": lambda state: state.has("Tree Zone Secret", self.player),
"Tree Zone 2 -> Tree Zone 3": lambda state: has_level_progression(state, "Tree Zone Progression", self.player, 2),
"Tree Zone 4 -> Tree Zone 5": lambda state: has_level_progression(state, "Tree Zone Progression", self.player, 3),
"Macro Zone 1 -> Macro Zone Secret Course": lambda state: state.has("Macro Zone Secret 1", self.player),
"Macro Zone Secret Course -> Macro Zone 4": lambda state: state.has("Macro Zone Secret 2", self.player),
"Macro Zone 1 -> Macro Zone 2": lambda state: has_level_progression(state, "Macro Zone Progression", self.player),
"Macro Zone 2 -> Macro Zone 3": lambda state: has_level_progression(state, "Macro Zone Progression", self.player, 2),
"Macro Zone 3 -> Macro Zone 4": lambda state: has_level_progression(state, "Macro Zone Progression", self.player, 3),
"Macro Zone 4 -> Macro Zone Secret Course": lambda state: state.has("Macro Zone Secret 2", self.player),
"Pumpkin Zone 1 -> Pumpkin Zone 2": lambda state: has_level_progression(state, "Pumpkin Zone Progression", self.player),
"Pumpkin Zone 2 -> Pumpkin Zone Secret Course 1": lambda state: state.has("Pumpkin Zone Secret 1", self.player),
"Pumpkin Zone 2 -> Pumpkin Zone 3": lambda state: has_level_progression(state, "Pumpkin Zone Progression", self.player, 2),
"Pumpkin Zone 3 -> Pumpkin Zone Secret Course 2": lambda state: state.has("Pumpkin Zone Secret 2", self.player),
"Pumpkin Zone 3 -> Pumpkin Zone 4": lambda state: has_level_progression(state, "Pumpkin Zone Progression", self.player, 3),
"Mario Zone 1 -> Mario Zone 2": lambda state: has_level_progression(state, "Mario Zone Progression", self.player),
"Mario Zone 2 -> Mario Zone 3": lambda state: has_level_progression(state, "Mario Zone Progression", self.player, 2),
"Mario Zone 3 -> Mario Zone 4": lambda state: has_level_progression(state, "Mario Zone Progression", self.player, 3),
"Turtle Zone 1 -> Turtle Zone 2": lambda state: has_level_progression(state, "Turtle Zone Progression", self.player),
"Turtle Zone 2 -> Turtle Zone Secret Course": lambda state: state.has("Turtle Zone Secret", self.player),
"Turtle Zone 2 -> Turtle Zone 3": lambda state: has_level_progression(state, "Turtle Zone Progression", self.player, 2),
}
if self.options.shuffle_golden_coins == "mario_coin_fragment_hunt":
# Require the other coins just to ensure they are being added to start inventory properly,
# and so they show up in Playthrough as required
entrance_rules["Menu -> Mario's Castle"] = lambda state: (state.has_all(
["Tree Coin", "Space Coin", "Macro Coin", "Pumpkin Coin", "Turtle Coin"], self.player)
and state.has("Mario Coin Fragment", self.player, self.coin_fragments_required))
else:
entrance_rules["Menu -> Mario's Castle"] = lambda state: state.has_from_list_unique([
"Tree Coin", "Space Coin", "Macro Coin", "Pumpkin Coin", "Mario Coin", "Turtle Coin"
], self.player, self.options.required_golden_coins)
for entrance, rule in entrance_rules.items():
self.multiworld.get_entrance(entrance, self.player).access_rule = rule
for location in self.multiworld.get_locations(self.player):
if location.name.endswith(("Coins", "Coin")):
rule = getattr(logic, location.parent_region.name.lower().replace(" ", "_") + "_coins", None)
if rule:
coins = int(location.name.split(" ")[-2])
location.access_rule = lambda state, coin_rule=rule, num_coins=coins: \
coin_rule(state, self.player, num_coins)
else:
rule = getattr(logic, location.name.lower().replace(
" - ", "_").replace(" ", "_").replace("'", ""), None)
if rule:
location.access_rule = lambda state, loc_rule=rule: loc_rule(state, self.player)
self.multiworld.completion_condition[self.player] = lambda state: state.has("Wario Defeated", self.player)
def create_items(self):
item_counts = {
"Space Zone Progression": 1,
"Space Zone Secret": 1,
"Tree Zone Progression": 3,
"Tree Zone Secret": 1,
"Macro Zone Progression": 3,
"Macro Zone Secret 1": 1,
"Macro Zone Secret 2": 1,
"Pumpkin Zone Progression": 3,
"Pumpkin Zone Secret 1": 1,
"Pumpkin Zone Secret 2": 1,
"Mario Zone Progression": 3,
"Turtle Zone Progression": 2,
"Turtle Zone Secret": 1,
"Mushroom": 1,
"Fire Flower": 1,
"Carrot": 1,
"Space Physics": 1,
"Hippo Bubble": 1,
"Water Physics": 1,
"Super Star Duration Increase": 2,
"Mario Coin Fragment": 0,
}
if self.options.shuffle_golden_coins == "mario_coin_fragment_hunt":
# There are 5 Zone Progression items that can be condensed.
item_counts["Mario Coin Fragment"] = 1 + ((5 * self.options.mario_coin_fragment_percentage) // 100)
if self.options.coinsanity:
coin_count = sum([level[1] for level in self.num_coin_locations])
max_coins = sum(self.max_coin_locations.values())
if self.options.shuffle_golden_coins == "mario_coin_fragment_hunt":
removed_coins = (coin_count * self.options.mario_coin_fragment_percentage) // 100
coin_count -= removed_coins
item_counts["Mario Coin Fragment"] += removed_coins
# Randomly remove some coin items for variety
coin_count -= (coin_count // self.random.randint(100, max(100, coin_count)))
if coin_count:
coin_bundle_sizes = [max_coins // coin_count] * coin_count
remainder = max_coins - sum(coin_bundle_sizes)
for i in range(remainder):
coin_bundle_sizes[i] += 1
for a, b in zip(range(1, len(coin_bundle_sizes), 2), range(2, len(coin_bundle_sizes), 2)):
split = self.random.randint(1, coin_bundle_sizes[a] + coin_bundle_sizes[b] - 1)
coin_bundle_sizes[a], coin_bundle_sizes[b] = split, coin_bundle_sizes[a] + coin_bundle_sizes[b] - split
for coin_bundle_size in coin_bundle_sizes:
item_name = f"{coin_bundle_size} Coin{'s' if coin_bundle_size > 1 else ''}"
if item_name in item_counts:
item_counts[item_name] += 1
else:
item_counts[item_name] = 1
if self.options.shuffle_golden_coins == "shuffle":
for item in self.item_name_groups["Golden Coins"]:
item_counts[item] = 1
elif self.options.shuffle_golden_coins == "mario_coin_fragment_hunt":
for item in ("Tree Coin", "Space Coin", "Macro Coin", "Pumpkin Coin", "Turtle Coin"):
self.multiworld.push_precollected(self.create_item(item))
else:
for item, location_name in (
("Mario Coin", "Mario Zone 4 - Boss"),
("Tree Coin", "Tree Zone 5 - Boss"),
("Space Coin", "Space Zone 2 - Boss"),
("Macro Coin", "Macro Zone 4 - Boss"),
("Pumpkin Coin", "Pumpkin Zone 4 - Boss"),
("Turtle Coin", "Turtle Zone 3 - Boss")
):
location = self.multiworld.get_location(location_name, self.player)
location.place_locked_item(self.create_item(item))
location.address = None
location.item.code = None
if self.options.shuffle_midway_bells:
for item in [item for item in items if "Midway Bell" in item]:
if item != "Mario's Castle Midway Bell" or self.options.marios_castle_midway_bell:
item_counts[item] = 1
if self.options.difficulty_mode == "easy_to_normal":
item_counts["Normal Mode"] = 1
elif self.options.difficulty_mode == "normal_to_easy":
item_counts["Easy Mode"] = 1
if self.options.shuffle_pipe_traversal == "single":
item_counts["Pipe Traversal"] = 1
elif self.options.shuffle_pipe_traversal == "split":
item_counts["Pipe Traversal - Right"] = 1
item_counts["Pipe Traversal - Left"] = 1
item_counts["Pipe Traversal - Up"] = 1
item_counts["Pipe Traversal - Down"] = 1
else:
self.multiworld.push_precollected(self.create_item("Pipe Traversal"))
if any(self.auto_scroll_levels):
if self.options.auto_scroll_mode == "global_trap_item":
item_counts["Auto Scroll"] = 1
elif self.options.auto_scroll_mode == "global_cancel_item":
item_counts["Cancel Auto Scroll"] = 1
else:
for level, i in enumerate(self.auto_scroll_levels):
if i == 3:
item_counts[f"Auto Scroll - {level_id_to_name[level]}"] = 1
elif i == 2:
item_counts[f"Cancel Auto Scroll - {level_id_to_name[level]}"] = 1
for item in self.multiworld.precollected_items[self.player]:
if item.name in item_counts and item_counts[item.name] > 0:
item_counts[item.name] -= 1
location_count = len(self.multiworld.get_unfilled_locations(self.player))
items_to_add = location_count - sum(item_counts.values())
if items_to_add > 0:
mario_coin_frags = 0
if self.options.shuffle_golden_coins == "mario_coin_fragment_hunt":
mario_coin_frags = (items_to_add * self.options.mario_coin_fragment_percentage) // 100
item_counts["Mario Coin Fragment"] += mario_coin_frags
item_counts["Super Star Duration Increase"] += items_to_add - mario_coin_frags
elif items_to_add < 0:
if self.options.coinsanity:
for i in range(1, 168):
coin_name = f"{i} Coin{'s' if i > 1 else ''}"
if coin_name in item_counts:
amount_to_remove = min(-items_to_add, item_counts[coin_name])
item_counts[coin_name] -= amount_to_remove
items_to_add += amount_to_remove
if items_to_add >= 0:
break
double_progression_items = ["Tree Zone Progression", "Macro Zone Progression", "Pumpkin Zone Progression",
"Mario Zone Progression", "Turtle Zone Progression"]
self.random.shuffle(double_progression_items)
while sum(item_counts.values()) > location_count:
if double_progression_items:
double_progression_item = double_progression_items.pop()
item_counts[double_progression_item] -= 2
item_counts[double_progression_item + " x2"] = 1
continue
if self.options.auto_scroll_mode in ("level_trap_items", "level_cancel_items",
"chaos"):
auto_scroll_item = self.random.choice([item for item in item_counts if "Auto Scroll" in item])
level = auto_scroll_item.split("- ")[1]
self.auto_scroll_levels[level_name_to_id[level]] = 0
del item_counts[auto_scroll_item]
continue
raise Exception(f"Too many items in the item pool for Super Mario Land 2 player {self.player_name}")
# item = self.random.choice(list(item_counts))
# item_counts[item] -= 1
# if item_counts[item] == 0:
# del item_counts[item]
# self.multiworld.push_precollected(self.create_item(item))
self.coin_fragments_required = max((item_counts["Mario Coin Fragment"]
* self.options.mario_coin_fragments_required_percentage) // 100, 1)
for item_name, count in item_counts.items():
self.multiworld.itempool += [self.create_item(item_name) for _ in range(count)]
def fill_slot_data(self):
return {
"energy_link": self.options.energy_link.value
}
def create_item(self, name: str) -> Item:
return MarioLand2Item(name, items[name], self.item_name_to_id[name], self.player)
def get_filler_item_name(self):
return "1 Coin"
def modify_multidata(self, multidata: dict):
rom_name = bytearray(f'AP{Utils.__version__.replace(".", "")[0:3]}_{self.player}_{self.multiworld.seed:11}\0',
'utf8')[:21]
rom_name.extend([0] * (21 - len(rom_name)))
new_name = base64.b64encode(bytes(rom_name)).decode()
multidata["connect_names"][new_name] = multidata["connect_names"][self.player_name]
class MarioLand2Location(Location):
game = "Super Mario Land 2"
class MarioLand2Item(Item):
game = "Super Mario Land 2"

Binary file not shown.

250
worlds/marioland2/client.py Normal file
View File

@@ -0,0 +1,250 @@
import base64
import logging
from NetUtils import ClientStatus
from worlds._bizhawk.client import BizHawkClient
from worlds._bizhawk import read, write, guarded_write
from .rom_addresses import rom_addresses
logger = logging.getLogger("Client")
BANK_EXCHANGE_RATE = 20000000000
overworld_music = (0x05, 0x06, 0x0D, 0x0E, 0x10, 0x12, 0x1B, 0x1C, 0x1E)
class MarioLand2Client(BizHawkClient):
system = ("GB", "SGB")
patch_suffix = ".apsml2"
game = "Super Mario Land 2"
def __init__(self):
super().__init__()
self.locations_array = []
self.previous_level = None
async def validate_rom(self, ctx):
game_name = await read(ctx.bizhawk_ctx, [(0x134, 10, "ROM")])
game_name = game_name[0].decode("ascii")
if game_name == "MARIOLAND2":
ctx.game = self.game
ctx.items_handling = 0b111
return True
return False
async def set_auth(self, ctx):
auth_name = await read(ctx.bizhawk_ctx, [(0x77777, 21, "ROM")])
auth_name = base64.b64encode(auth_name[0]).decode()
ctx.auth = auth_name
async def game_watcher(self, ctx):
from . import START_IDS
from .items import items
from .locations import locations, level_id_to_name, coins_coords, location_name_to_id
(game_loaded_check, level_data, music, auto_scroll_levels, current_level,
midway_point, bcd_lives, num_items_received, coins, options) = \
await read(ctx.bizhawk_ctx, [(0x0046, 10, "CartRAM"), (0x0848, 42, "CartRAM"), (0x0469, 1, "CartRAM"),
(rom_addresses["Auto_Scroll_Levels_B"], 32, "ROM"),
(0x0269, 1, "CartRAM"), (0x02A0, 1, "CartRAM"), (0x022C, 1, "CartRAM"),
(0x00F0, 2, "CartRAM"), (0x0262, 2, "CartRAM"),
(rom_addresses["Coins_Required"], 8, "ROM")])
coins_required = int.from_bytes(options[:2], "big")
difficulty_mode = options[2]
star_count = int.from_bytes(options[3:5], "big")
midway_bells = options[5]
energy_link = options[6]
coin_mode = options[7]
current_level = int.from_bytes(current_level, "big")
auto_scroll_levels = list(auto_scroll_levels)
midway_point = int.from_bytes(midway_point, "big")
music = int.from_bytes(music, "big")
level_data = list(level_data)
lives = bcd_lives.hex()
num_items_received = int.from_bytes(num_items_received, "big")
if num_items_received == 0xFFFF:
num_items_received = 0
items_received = [list(items.keys())[item.item - START_IDS] for item in ctx.items_received]
write_num_items_received = len(items_received).to_bytes(2, "big")
level_progression = {
"Space Zone Progression",
"Tree Zone Progression",
"Macro Zone Progression",
"Pumpkin Zone Progression",
"Mario Zone Progression",
"Turtle Zone Progression",
}
for level_item in level_progression:
for _ in range(items_received.count(level_item + " x2")):
items_received += ([level_item] * 2)
if "Pipe Traversal" in items_received:
items_received += ["Pipe Traversal - Left", "Pipe Traversal - Right",
"Pipe Traversal - Up", "Pipe Traversal - Down"]
if coin_mode == 2 and items_received.count("Mario Coin Fragment") >= coins_required:
items_received.append("Mario Coin")
if current_level == 255 and self.previous_level != 255:
if coin_mode < 2:
logger.info(f"Golden Coins required: {coins_required}")
else:
logger.info(f"Mario Coin Fragments required: {coins_required}. "
f"You have {items_received.count('Mario Coin Fragment')}")
self.previous_level = current_level
# There is no music in the title screen demos, this is how we guard against anything in the demos registering.
# There is also no music at the door to Mario's Castle, which is why the above is before this check.
if game_loaded_check != b'\x124Vx\xff\xff\xff\xff\xff\xff' or music == 0:
return
locations_checked = []
if current_level in level_id_to_name:
level_name = level_id_to_name[current_level]
coin_tile_data = await read(ctx.bizhawk_ctx, [(0xB000 + ((coords[1] * 256) + coords[0]), 1, "System Bus")
for coords in coins_coords[level_name]])
num_coins = len([tile[0] for tile in coin_tile_data if tile[0] in (0x7f, 0x60, 0x07)])
locations_checked = [location_name_to_id[f"{level_name} - {i} Coin{'s' if i > 1 else ''}"]
for i in range(1, num_coins + 1)]
new_lives = int(lives)
energy_link_add = None
if energy_link:
if new_lives == 0:
if (f"EnergyLink{ctx.team}" in ctx.stored_data
and ctx.stored_data[f"EnergyLink{ctx.team}"]
and ctx.stored_data[f"EnergyLink{ctx.team}"] >= BANK_EXCHANGE_RATE):
new_lives = 1
energy_link_add = -BANK_EXCHANGE_RATE
elif new_lives > 1:
energy_link_add = BANK_EXCHANGE_RATE * (new_lives - 1)
new_lives = 1
# Convert back to binary-coded-decimal
new_lives = int(str(new_lives), 16)
new_coins = coins.hex()
new_coins = int(new_coins[2:] + new_coins[:2])
for item in items_received[num_items_received:]:
if item.endswith("Coins") or item == "1 Coin":
new_coins += int(item.split(" ")[0])
# Limit to 999 and convert back to binary-coded-decimal
new_coins = int(str(min(new_coins, 999)), 16).to_bytes(2, "little")
modified_level_data = level_data.copy()
for ID, (location, data) in enumerate(locations.items(), START_IDS):
if "clear_condition" in data:
if items_received.count(data["clear_condition"][0]) >= data["clear_condition"][1]:
modified_level_data[data["ram_index"]] |= (0x08 if data["type"] == "bell"
else 0x01 if data["type"] == "secret" else 0x80)
if data["type"] == "level" and level_data[data["ram_index"]] & 0x40:
locations_checked.append(ID)
if data["type"] == "secret" and level_data[data["ram_index"]] & 0x02:
locations_checked.append(ID)
elif data["type"] == "bell" and data["id"] == current_level and midway_point == 0xFF:
locations_checked.append(ID)
invincibility_length = int((832.0 / (star_count + 1))
* (items_received.count("Super Star Duration Increase") + 1))
if "Easy Mode" in items_received:
difficulty_mode = 1
elif "Normal Mode" in items_received:
difficulty_mode = 0
data_writes = [
(rom_addresses["Space_Physics"], [0x7e] if "Space Physics" in items_received else [0xaf], "ROM"),
(rom_addresses["Get_Hurt_To_Big_Mario"], [1] if "Mushroom" in items_received else [0], "ROM"),
(rom_addresses["Get_Mushroom_A"], [0xea, 0x16, 0xa2] if "Mushroom" in items_received else [0, 0, 0], "ROM"),
(rom_addresses["Get_Mushroom_B"], [0xea, 0x16, 0xa2] if "Mushroom" in items_received else [0, 0, 0], "ROM"),
(rom_addresses["Get_Mushroom_C"], [00] if "Mushroom" in items_received else [0xd8], "ROM"),
(rom_addresses["Get_Carrot_A"], [0xea, 0x16, 0xa2] if "Carrot" in items_received else [0, 0, 0], "ROM"),
(rom_addresses["Get_Carrot_B"], [0xea, 0x16, 0xa2] if "Carrot" in items_received else [0, 0, 0], "ROM"),
(rom_addresses["Get_Carrot_C"], [00] if "Carrot" in items_received else [0xc8], "ROM"),
(rom_addresses["Get_Fire_Flower_A"], [0xea, 0x16, 0xa2] if "Fire Flower" in items_received else [0, 0, 0], "ROM"),
(rom_addresses["Get_Fire_Flower_B"], [0xea, 0x16, 0xa2] if "Fire Flower" in items_received else [0, 0, 0], "ROM"),
(rom_addresses["Get_Fire_Flower_C"], [00] if "Fire Flower" in items_received else [0xc8], "ROM"),
(rom_addresses["Invincibility_Star_A"], [(invincibility_length >> 8) + 1], "ROM"),
(rom_addresses["Invincibility_Star_B"], [invincibility_length & 0xFF], "ROM"),
(rom_addresses["Enable_Bubble"], [0xcb, 0xd7] if "Hippo Bubble" in items_received else [0, 0], "ROM"),
(rom_addresses["Enable_Swim"], [0xcb, 0xcf] if "Water Physics" in items_received else [0, 0], "ROM"),
(rom_addresses["Pipe_Traversal_A"], [16] if "Pipe Traversal - Down" in items_received else [0], "ROM"),
(rom_addresses["Pipe_Traversal_B"], [32] if "Pipe Traversal - Up" in items_received else [10], "ROM"),
(rom_addresses["Pipe_Traversal_C"], [48] if "Pipe Traversal - Right" in items_received else [0], "ROM"),
(rom_addresses["Pipe_Traversal_D"], [64] if "Pipe Traversal - Left" in items_received else [0], "ROM"),
(rom_addresses["Pipe_Traversal_SFX_A"], [5] if "Pipe Traversal - Down" in items_received else [0], "ROM"),
(rom_addresses["Pipe_Traversal_SFX_B"], [5] if "Pipe Traversal - Up" in items_received else [0], "ROM"),
(rom_addresses["Pipe_Traversal_SFX_C"], [5] if "Pipe Traversal - Right" in items_received else [0], "ROM"),
(rom_addresses["Pipe_Traversal_SFX_D"], [5] if "Pipe Traversal - Left" in items_received else [0], "ROM"),
(0x022c, [new_lives], "CartRAM"),
(0x02E4, [difficulty_mode], "CartRAM"),
(0x0848, modified_level_data, "CartRAM"),
(0x0262, new_coins, "CartRAM"),
]
if items_received:
data_writes.append((0x00F0, write_num_items_received, "CartRAM"))
if midway_point == 0xFF and (midway_bells or music in overworld_music):
# after registering the check for the midway bell, clear the value just for safety.
data_writes.append((0x02A0, [0], "CartRAM"))
for i in range(32):
if auto_scroll_levels[i] == 3:
if "Auto Scroll" in items_received or f"Auto Scroll - {level_id_to_name[i]}" in items_received:
auto_scroll_levels[i] = 1
if i == current_level:
data_writes.append((0x02C8, [0x01], "CartRAM"))
else:
auto_scroll_levels[i] = 0
elif auto_scroll_levels[i] == 2:
if ("Cancel Auto Scroll" in items_received
or f"Cancel Auto Scroll - {level_id_to_name[i]}" in items_received):
auto_scroll_levels[i] = 0
if i == current_level:
data_writes.append((0x02C8, [0x00], "CartRAM"))
else:
auto_scroll_levels[i] = 1
data_writes.append((rom_addresses["Auto_Scroll_Levels"], auto_scroll_levels, "ROM"))
success = await guarded_write(ctx.bizhawk_ctx, data_writes, [(0x0848, level_data, "CartRAM"),
(0x022C, [int.from_bytes(bcd_lives, "big")],
"CartRAM"),
[0x0262, coins, "CartRAM"]])
if success and energy_link_add is not None:
await ctx.send_msgs([{
"cmd": "Set", "key": f"EnergyLink{ctx.team}", "operations":
[{"operation": "add", "value": energy_link_add},
{"operation": "max", "value": 0}],
}])
if not ctx.server or not ctx.server.socket.open or ctx.server.socket.closed:
return
if locations_checked and locations_checked != self.locations_array:
self.locations_array = locations_checked
await ctx.send_msgs([{"cmd": "LocationChecks", "locations": locations_checked}])
if music == 0x18:
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
ctx.finished_game = True
def on_package(self, ctx, cmd: str, args: dict):
super().on_package(ctx, cmd, args)
if cmd == 'Connected':
if ctx.slot_data["energy_link"]:
ctx.set_notify(f"EnergyLink{ctx.team}")
if ctx.ui:
ctx.ui.enable_energy_link()
ctx.ui.energy_link_label.text = "Lives: Standby"
elif cmd == "SetReply" and args["key"].startswith("EnergyLink"):
if ctx.ui:
ctx.ui.energy_link_label.text = f"Lives: {int(args['value'] / BANK_EXCHANGE_RATE)}"
elif cmd == "Retrieved":
if f"EnergyLink{ctx.team}" in args["keys"] and args['keys'][f'EnergyLink{ctx.team}'] and ctx.ui:
ctx.ui.energy_link_label.text = f"Lives: {int(args['keys'][f'EnergyLink{ctx.team}'] / BANK_EXCHANGE_RATE)}"

View File

@@ -0,0 +1,64 @@
# Super Mario Land 2: 6 Golden Coins
## 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 items and locations get shuffled?
Completing a level's exits results in a location check instead of automatically bringing you to the next level.
Where there are secret exits, the secret exit will be a separate location check. There is one exception, Hippo Zone,
that does not have a separate check for its secret exit. The Hippo Zone secret exit will still bring you to the Space
Zone.
Ringing the Midway Bells in each level that has one will register a location check. If the "Shuffle Midway Bells" option
is turned on, then ringing the bell will not grant the checkpoint, and instead you must obtain the Midway Bell item from
the item pool to gain the checkpoint for that level. Holding SELECT while loading into a level where you have unlocked
the Midway Bell checkpoint will start you at the beginning of the level.
Unlocking paths to new levels requires finding or receiving Zone Progression items. For example, receiving the first
"Turtle Zone Progression" will unlock the path from Turtle Zone 1 to Turtle Zone 2. Paths to secret levels are separate
items, so Turtle Zone Secret will open the path from Turtle Zone 2 to the Turtle Zone Secret Course.
Depending on settings, there may be some "Zone Progression x2" items that open two paths at once.
The path from Tree Zone 2 to the branch to Tree Zone 3 and 4 is one unlock, so both levels will open at this point.
Besides the zone progression unlocks, the following items are always shuffled:
- Mushroom: required to become Big Mario. If you are Fire or Bunny Mario and take damage, and have not obtained the
Mushroom, you will drop straight down to Small Mario.
- Fire Flower: required to become Fire Mario.
- Carrot: required to become Bunny Mario.
- Hippo Bubble: required to use the bubbles in Hippo Zone to fly.
- Water Physics: Mario will fall through water as though it is air until this is obtained.
- Space Physics: the Space Zone levels will have normal gravity until this is obtained.
- Super Star Duration Increase: you begin with a drastically lowered invincibility star duration, and these items will
increase it.
Additionally, the following items can be shuffled depending on your YAML options:
- The 6 Golden Coins: note that the game will still show you the coin being sent to the castle when defeating a boss
regardless of whether the coin is actually obtained in that location.
- Mario Coin Fragments: As an alternative to shuffling the 6 Golden Coins, you can shuffle Mario Coin Fragments,
a chosen percentage of which are needed to assemble the Mario Coin. You will start with the other 5 coins.
- Normal Mode/Easy Mode: you can start the game in Normal Mode with an Easy Mode "upgrade" in the item pool, or start in
Easy Mode with a Normal Mode "trap" item, swapping the difficulty.
- Auto Scroll: auto-scrolling levels can be set to not auto scroll until this trap item is received.
- Pipe Traversal: required to enter pipes. Can also be split into 4 items, each enabling pipe entry from a different
direction.
- Coins: if Coinsanity is enabled, coins will be shuffled into the item pool. A number of checks will be added to each
level for obtaining a specific number of coins within a single playthrough of the level.
## When the player receives an item, what happens?
There is no in-game indication that an item has been received. You will need to watch the client or web tracker to be
sure you're aware of the items you've received.
## Special Thanks to:
- [froggestspirit](https://github.com/froggestspirit) for his Super Mario Land 2 disassembly. While very incomplete, it
had enough memory values mapped out to make my work significantly easier.
- [slashinfty](https://github.com/slashinfty), the author of the
[Super Mario Land 2 Randomizer](https://sml2r.download/) for permitting me to port features such as Randomize Enemies
and Randomize Platforms directly from it.

View File

@@ -0,0 +1,75 @@
# Setup Guide for Super Mario Land 2: 6 Golden Coins
## 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 prereq installer first, which can also be found at the above link.
- The built-in Archipelago client, which can be installed [here](https://github.com/ArchipelagoMW/Archipelago/releases)
- A Super Mario Land 2: 6 Golden Coins version 1.0 ROM file. The Archipelago community cannot provide this.
## Configuring BizHawk
Once BizHawk has been installed, open EmuHawk and change the following settings:
- Under Config > Customize > Advanced, make sure the box for AutoSaveRAM is checked, and click the 5s button.
This reduces the possibility of losing save data in emulator crashes.
- Under Config > Customize, check the "Run in background" box. This will prevent disconnecting from the client while
EmuHawk is running in the background.
It is strongly recommended to associate Game Boy ROM extensions (\*.gb) to the EmuHawk we've just installed.
To do so, we simply have to search any Game Boy ROM we happened to own, right click and select "Open with...", unfold
the list that appears and select the bottom option "Look for another application", then browse to the BizHawk folder
and select EmuHawk.exe.
## 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 generate a yaml or download a template by visiting the [Super Mario Land 2 Player Options Page](/games/Super%20Mario%20Land%202/player-options)
## Joining a MultiWorld Game
### Generating and Patching a Game
1. Create your options file (YAML).
2. Follow the general Archipelago instructions for [generating a game](../../Archipelago/setup/en#generating-a-game).
This will generate an output file for you. Your patch file will have a `.apsml2` file extension.
3. Open `ArchipelagoLauncher.exe`
4. Select "Open Patch" on the left side and select your patch file.
5. If this is your first time patching, you will be prompted to locate your vanilla ROM.
6. A patched `.gb` file will be created in the same place as the patch file.
7. On your first time opening a patch with BizHawk Client, you will also be asked to locate `EmuHawk.exe` in your
BizHawk install.
You must connect Super Mario Land 2 to a server, even for a single player game, or progress cannot be made.
### Connect to the Multiserver
By default, opening a patch file will do steps 1-5 below for you automatically. Even so, keep them in your memory just
in case you have to close and reopen a window mid-game for some reason.
1. Super Mario Land 2 uses Archipelago's BizHawk Client. If the client isn't still open from when you patched your
game, you can re-open it from the launcher.
2. Ensure EmuHawk is running the patched ROM.
3. In EmuHawk, go to `Tools > Lua Console`. This window must stay open while playing.
4. In the Lua Console window, go to `Script > Open Script…`.
5. Navigate to your Archipelago install folder and open `data/lua/connector_bizhawk_generic.lua`.
6. The emulator may freeze every few seconds until it manages to connect to the client. This is expected. The BizHawk
Client window should indicate that it connected and recognized Super Mario Land 2.
7. To connect the client to the server, enter your room's address and port (e.g. `archipelago.gg:38281`) into the
top text field of the client and click Connect.
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]`)

View File

@@ -0,0 +1,79 @@
from BaseClasses import ItemClassification
from .locations import level_name_to_id
from .options import CoinsanityChecks
items = {
"Space Zone Progression": ItemClassification.progression,
"Space Zone Secret": ItemClassification.progression,
"Tree Zone Progression": ItemClassification.progression,
"Tree Zone Progression x2": ItemClassification.progression,
"Tree Zone Secret": ItemClassification.progression,
"Macro Zone Progression": ItemClassification.progression,
"Macro Zone Progression x2": ItemClassification.progression,
"Macro Zone Secret 1": ItemClassification.progression,
"Macro Zone Secret 2": ItemClassification.progression_skip_balancing,
"Pumpkin Zone Progression": ItemClassification.progression,
"Pumpkin Zone Progression x2": ItemClassification.progression,
"Pumpkin Zone Secret 1": ItemClassification.progression,
"Pumpkin Zone Secret 2": ItemClassification.progression,
"Mario Zone Progression": ItemClassification.progression,
"Mario Zone Progression x2": ItemClassification.progression,
"Turtle Zone Progression": ItemClassification.progression,
"Turtle Zone Progression x2": ItemClassification.progression,
"Turtle Zone Secret": ItemClassification.progression,
"Tree Coin": ItemClassification.progression_skip_balancing,
"Space Coin": ItemClassification.progression_skip_balancing,
"Macro Coin": ItemClassification.progression_skip_balancing,
"Pumpkin Coin": ItemClassification.progression_skip_balancing,
"Mario Coin": ItemClassification.progression_skip_balancing,
"Turtle Coin": ItemClassification.progression_skip_balancing,
"Mario Coin Fragment": ItemClassification.progression_skip_balancing,
"Mushroom": ItemClassification.progression,
"Fire Flower": ItemClassification.progression,
"Carrot": ItemClassification.progression,
"Space Physics": ItemClassification.progression_skip_balancing,
"Hippo Bubble": ItemClassification.progression_skip_balancing,
"Water Physics": ItemClassification.progression,
"Pipe Traversal": ItemClassification.progression,
"Pipe Traversal - Down": ItemClassification.progression,
"Pipe Traversal - Up": ItemClassification.progression,
"Pipe Traversal - Right": ItemClassification.progression,
"Pipe Traversal - Left": ItemClassification.progression_skip_balancing,
"Super Star Duration Increase": ItemClassification.filler,
"Easy Mode": ItemClassification.useful,
"Normal Mode": ItemClassification.trap,
"Auto Scroll": ItemClassification.trap,
**{f"Auto Scroll - {level}": ItemClassification.trap for level in level_name_to_id if level != "Wario's Castle"},
"Cancel Auto Scroll": ItemClassification.progression,
**{f"Cancel Auto Scroll - {level}": ItemClassification.progression for level in level_name_to_id
if level != "Wario's Castle"},
"Mushroom Zone Midway Bell": ItemClassification.filler,
"Tree Zone 1 Midway Bell": ItemClassification.filler,
"Tree Zone 2 Midway Bell": ItemClassification.progression_skip_balancing,
"Tree Zone 4 Midway Bell": ItemClassification.progression_skip_balancing,
"Tree Zone 5 Midway Bell": ItemClassification.filler,
"Space Zone 1 Midway Bell": ItemClassification.filler,
"Space Zone 2 Midway Bell": ItemClassification.progression_skip_balancing,
"Macro Zone 1 Midway Bell": ItemClassification.progression_skip_balancing,
"Macro Zone 2 Midway Bell": ItemClassification.progression_skip_balancing,
"Macro Zone 3 Midway Bell": ItemClassification.progression_skip_balancing,
"Macro Zone 4 Midway Bell": ItemClassification.filler,
"Pumpkin Zone 1 Midway Bell": ItemClassification.progression_skip_balancing,
"Pumpkin Zone 2 Midway Bell": ItemClassification.filler,
"Pumpkin Zone 3 Midway Bell": ItemClassification.filler,
"Pumpkin Zone 4 Midway Bell": ItemClassification.filler,
"Mario Zone 1 Midway Bell": ItemClassification.progression_skip_balancing,
"Mario Zone 2 Midway Bell": ItemClassification.filler,
"Mario Zone 3 Midway Bell": ItemClassification.filler,
"Mario Zone 4 Midway Bell": ItemClassification.filler,
"Turtle Zone 1 Midway Bell": ItemClassification.filler,
"Turtle Zone 2 Midway Bell": ItemClassification.progression_skip_balancing,
"Turtle Zone 3 Midway Bell": ItemClassification.filler,
"Mario's Castle Midway Bell": ItemClassification.progression_skip_balancing,
"1 Coin": ItemClassification.filler,
**{f"{i} Coins": ItemClassification.filler for i in range(2, CoinsanityChecks.range_end + 1)}
}
for level in {"Turtle Zone Secret Course", "Macro Zone Secret Course", "Turtle Zone 3", "Scenic Course",
"Mario Zone 2"}:
items[f"Cancel Auto Scroll - {level}"] = ItemClassification.useful

View File

@@ -0,0 +1,498 @@
START_IDS = 1
locations = {
"Mushroom Zone - Normal Exit": {"id": 0x00, "ram_index": 0, "type": "level"},
"Mushroom Zone - Midway Bell": {"id": 0x00, "ram_index": 0, "clear_condition": ("Mushroom Zone Midway Bell", 1), "type": "bell"},
"Scenic Course - Normal Exit": {"id": 0x19, "ram_index": 40, "type": "level"},
"Tree Zone 1 - Normal Exit": {"id": 0x01, "ram_index": 1, "clear_condition": ("Tree Zone Progression", 1), "type": "level"},
"Tree Zone 1 - Midway Bell": {"id": 0x01, "ram_index": 1, "clear_condition": ("Tree Zone 1 Midway Bell", 1), "type": "bell"},
"Tree Zone 2 - Normal Exit": {"id": 0x02, "ram_index": 2, "clear_condition": ("Tree Zone Progression", 2), "type": "level"},
"Tree Zone 2 - Secret Exit": {"id": 0x02, "ram_index": 2, "clear_condition": ("Tree Zone Secret", 1), "type": "secret"},
"Tree Zone 2 - Midway Bell": {"id": 0x02, "ram_index": 2, "clear_condition": ("Tree Zone 2 Midway Bell", 1), "type": "bell"},
"Tree Zone 3 - Normal Exit": {"id": 0x04, "ram_index": 4, "clear_condition": ("Tree Zone Progression", 3), "type": "level"},
"Tree Zone 4 - Normal Exit": {"id": 0x03, "ram_index": 3, "clear_condition": ("Tree Zone Progression", 3), "type": "level"},
"Tree Zone 4 - Midway Bell": {"id": 0x03, "ram_index": 3, "clear_condition": ("Tree Zone 4 Midway Bell", 1), "type": "bell"},
"Tree Zone 5 - Boss": {"id": 0x05, "ram_index": 5, "clear_condition": ("Tree Coin", 1), "type": "level"},
"Tree Zone 5 - Midway Bell": {"id": 0x05, "ram_index": 5, "clear_condition": ("Tree Zone 5 Midway Bell", 1), "type": "bell"},
"Tree Zone Secret Course - Normal Exit": {"id": 0x1D, "ram_index": 36, "type": "level"},
"Hippo Zone - Normal or Secret Exit": {"id": 0x11, "ram_index": 31, "type": "level"},
"Space Zone 1 - Normal Exit": {"id": 0x12, "ram_index": 16, "clear_condition": ("Space Zone Progression", 1), "type": "level"},
"Space Zone 1 - Secret Exit": {"id": 0x12, "ram_index": 16, "clear_condition": ("Space Zone Secret", 1), "type": "secret"},
"Space Zone 1 - Midway Bell": {"id": 0x12, "ram_index": 16, "clear_condition": ("Space Zone 1 Midway Bell", 1), "type": "bell"},
"Space Zone Secret Course - Normal Exit": {"id": 0x1C, "ram_index": 41, "type": "level"},
"Space Zone 2 - Boss": {"id": 0x13, "ram_index": 17, "clear_condition": ("Space Coin", 1), "type": "level"},
"Space Zone 2 - Midway Bell": {"id": 0x13, "ram_index": 17, "clear_condition": ("Space Zone 2 Midway Bell", 1), "type": "bell"},
"Macro Zone 1 - Normal Exit": {"id": 0x14, "ram_index": 11, "clear_condition": ("Macro Zone Progression", 1), "type": "level"},
"Macro Zone 1 - Secret Exit": {"id": 0x14, "ram_index": 11, "clear_condition": ("Macro Zone Secret 1", 1), "type": "secret"},
"Macro Zone 1 - Midway Bell": {"id": 0x14, "ram_index": 11, "clear_condition": ("Macro Zone 1 Midway Bell", 1), "type": "bell"},
"Macro Zone 2 - Normal Exit": {"id": 0x15, "ram_index": 12, "clear_condition": ("Macro Zone Progression", 2), "type": "level"},
"Macro Zone 2 - Midway Bell": {"id": 0x15, "ram_index": 12, "clear_condition": ("Macro Zone 2 Midway Bell", 1), "type": "bell"},
"Macro Zone 3 - Normal Exit": {"id": 0x16, "ram_index": 13, "clear_condition": ("Macro Zone Progression", 3), "type": "level"},
"Macro Zone 3 - Midway Bell": {"id": 0x16, "ram_index": 13, "clear_condition": ("Macro Zone 3 Midway Bell", 1), "type": "bell"},
"Macro Zone 4 - Boss": {"id": 0x17, "ram_index": 14, "clear_condition": ("Macro Coin", 1), "type": "level"},
"Macro Zone 4 - Midway Bell": {"id": 0x17, "ram_index": 14, "clear_condition": ("Macro Zone 4 Midway Bell", 1), "type": "bell"},
"Macro Zone Secret Course - Normal Exit": {"id": 0x1E, "ram_index": 35, "clear_condition": ("Macro Zone Secret 2", 1), "type": "level"},
"Pumpkin Zone 1 - Normal Exit": {"id": 0x06, "ram_index": 6, "clear_condition": ("Pumpkin Zone Progression", 1), "type": "level"},
"Pumpkin Zone 1 - Midway Bell": {"id": 0x06, "ram_index": 6, "clear_condition": ("Pumpkin Zone 1 Midway Bell", 1), "type": "bell"},
"Pumpkin Zone 2 - Normal Exit": {"id": 0x07, "ram_index": 7, "clear_condition": ("Pumpkin Zone Progression", 2), "type": "level"},
"Pumpkin Zone 2 - Secret Exit": {"id": 0x07, "ram_index": 7, "clear_condition": ("Pumpkin Zone Secret 1", 1), "type": "secret"},
"Pumpkin Zone 2 - Midway Bell": {"id": 0x07, "ram_index": 7, "clear_condition": ("Pumpkin Zone 2 Midway Bell", 2), "type": "bell"},
"Pumpkin Zone 3 - Normal Exit": {"id": 0x08, "ram_index": 8, "clear_condition": ("Pumpkin Zone Progression", 3), "type": "level"},
"Pumpkin Zone 3 - Secret Exit": {"id": 0x08, "ram_index": 8, "clear_condition": ("Pumpkin Zone Secret 2", 1), "type": "secret"},
"Pumpkin Zone 3 - Midway Bell": {"id": 0x08, "ram_index": 8, "clear_condition": ("Pumpkin Zone 3 Midway Bell", 3), "type": "bell"},
"Pumpkin Zone 4 - Boss": {"id": 0x09, "ram_index": 9, "clear_condition": ("Pumpkin Coin", 1), "type": "level"},
"Pumpkin Zone 4 - Midway Bell": {"id": 0x09, "ram_index": 9, "clear_condition": ("Pumpkin Zone 4 Midway Bell", 1), "type": "bell"},
"Pumpkin Zone Secret Course 1 - Normal Exit": {"id": 0x1B, "ram_index": 38, "type": "level"},
"Pumpkin Zone Secret Course 2 - Normal Exit": {"id": 0x1F, "ram_index": 39, "type": "level"},
"Mario Zone 1 - Normal Exit": {"id": 0x0A, "ram_index": 26, "clear_condition": ("Mario Zone Progression", 1), "type": "level"},
"Mario Zone 1 - Midway Bell": {"id": 0x0A, "ram_index": 26, "clear_condition": ("Mario Zone 1 Midway Bell", 1), "type": "bell"},
"Mario Zone 2 - Normal Exit": {"id": 0x0B, "ram_index": 27, "clear_condition": ("Mario Zone Progression", 2), "type": "level"},
"Mario Zone 2 - Midway Bell": {"id": 0x0B, "ram_index": 27, "clear_condition": ("Mario Zone 2 Midway Bell", 1), "type": "bell"},
"Mario Zone 3 - Normal Exit": {"id": 0x0C, "ram_index": 28, "clear_condition": ("Mario Zone Progression", 3), "type": "level"},
"Mario Zone 3 - Midway Bell": {"id": 0x0C, "ram_index": 28, "clear_condition": ("Mario Zone 3 Midway Bell", 1), "type": "bell"},
"Mario Zone 4 - Boss": {"id": 0x0D, "ram_index": 29, "clear_condition": ("Mario Coin", 1), "type": "level"},
"Mario Zone 4 - Midway Bell": {"id": 0x0D, "ram_index": 29, "clear_condition": ("Mario Zone 4 Midway Bell", 1), "type": "bell"},
"Turtle Zone 1 - Normal Exit": {"id": 0x0E, "ram_index": 21, "clear_condition": ("Turtle Zone Progression", 1), "type": "level"},
"Turtle Zone 1 - Midway Bell": {"id": 0x0E, "ram_index": 21, "clear_condition": ("Turtle Zone 1 Midway Bell", 1), "type": "bell"},
"Turtle Zone 2 - Normal Exit": {"id": 0x0F, "ram_index": 22, "clear_condition": ("Turtle Zone Progression", 2), "type": "level"},
"Turtle Zone 2 - Secret Exit": {"id": 0x0F, "ram_index": 22, "clear_condition": ("Turtle Zone Secret", 1), "type": "secret"},
"Turtle Zone 2 - Midway Bell": {"id": 0x0F, "ram_index": 22, "clear_condition": ("Turtle Zone 2 Midway Bell", 1), "type": "bell"},
"Turtle Zone 3 - Boss": {"id": 0x10, "ram_index": 23, "clear_condition": ("Turtle Coin", 1), "type": "level"},
"Turtle Zone 3 - Midway Bell": {"id": 0x10, "ram_index": 23, "clear_condition": ("Turtle Zone 3 Midway Bell", 1), "type": "bell"},
"Turtle Zone Secret Course - Normal Exit": {"id": 0x1A, "ram_index": 37, "type": "level"},
"Mario's Castle - Midway Bell": {"id": 24, "ram_index": 24, "clear_condition": ("Mario's Castle Midway Bell", 1), "type": "bell"},
}
coins_coords = {
"Mushroom Zone":
[(22, 28), (24, 28), (42, 28), (43, 28), (74, 36), (74, 37), (74, 38), (76, 36), (76, 37),
(76, 38), (78, 36), (78, 37), (78, 38), (80, 36), (80, 37), (80, 38), (82, 36), (82, 37),
(82, 38), (83, 25), (84, 25), (84, 36), (84, 37), (84, 38), (85, 25), (86, 25), (86, 36),
(86, 37), (86, 38), (87, 25), (88, 36), (88, 37), (88, 38), (116, 24), (117, 24), (118, 24),
(151, 28), (152, 28), (180, 28), (181, 24), (181, 28), (182, 24), (182, 28), (183, 24), (183, 28),
(184, 24), (184, 28), (185, 24), (185, 28), (186, 24), (186, 28), (187, 24), (187, 28), (188, 24),
(188, 28), (189, 28), (211, 25), (212, 25), (212, 36), (212, 37), (212, 38), (212, 39), (213, 25),
(213, 36), (213, 37), (213, 38), (213, 39), (214, 25), (214, 36), (214, 37), (214, 38), (214, 39),
(215, 25), (216, 25), (217, 25), (217, 36), (217, 37), (217, 38), (217, 39), (218, 25), (218, 36),
(218, 37), (218, 38), (218, 39), (219, 25), (219, 36), (219, 37), (219, 38), (219, 39), (220, 25),
(231, 24), (232, 24)],
"Tree Zone 1":
[(27, 30), (28, 30), (29, 30), (33, 27), (34, 27), (35, 27), (40, 30), (41, 30), (42, 30), (47, 27),
(48, 27), (49, 27), (56, 30), (57, 30), (58, 30), (64, 30), (65, 30), (66, 30), (88, 30), (89, 30),
(90, 30), (94, 30), (95, 30), (96, 30), (100, 30), (101, 30), (102, 30), (106, 27), (107, 27),
(108, 27), (112, 30), (113, 30), (114, 30), (119, 28), (138, 30), (139, 30), (140, 30), (150, 28),
(151, 20), (151, 28), (152, 20), (152, 26), (152, 28), (153, 26), (153, 28), (154, 26), (154, 28),
(155, 26), (155, 28), (156, 26), (156, 28), (157, 20), (157, 26), (157, 28), (158, 20), (158, 26),
(158, 28), (159, 26), (159, 28), (160, 28), (161, 28), (176, 13), (177, 13), (177, 29), (178, 13),
(178, 29), (179, 13), (179, 29), (180, 13), (181, 13), (182, 13), (183, 13), (184, 13), (185, 13),
(186, 13), (187, 13), (187, 29), (188, 13), (188, 29), (189, 13), (189, 29), (190, 13), (191, 13),
(192, 13), (193, 13), (194, 13), (195, 13), (196, 13), (197, 13), (197, 29), (198, 13), (198, 29),
(199, 13), (199, 29), (200, 13), (201, 13), (202, 13), (203, 13), (204, 13), (205, 13), (206, 13),
(207, 27), (208, 13), (208, 27), (209, 14), (209, 27), (210, 10), (210, 11), (210, 12), (210, 13),
(210, 14), (210, 15), (211, 14), (212, 13), (219, 30), (220, 30), (221, 30), (229, 27), (230, 27),
(231, 27)],
"Tree Zone 2":
[(27, 11), (28, 11), (42, 10), (43, 10), (44, 10), (51, 28), (61, 9), (65, 26), (66, 26), (67, 26),
(70, 24), (71, 24), (72, 10), (72, 24), (73, 10), (73, 24), (75, 10), (76, 10), (76, 26), (77, 26),
(78, 10), (78, 26), (79, 10), (80, 24), (81, 10), (81, 24), (82, 10), (82, 24), (83, 24), (127, 7),
(128, 7), (129, 7), (130, 7), (136, 43), (138, 9), (138, 10), (138, 11), (139, 41), (140, 41),
(141, 41), (142, 9), (142, 10), (142, 11), (144, 41), (145, 41), (146, 9), (146, 10), (146, 11),
(146, 41), (149, 41), (150, 41), (151, 41), (154, 41), (155, 41), (156, 41), (159, 41), (160, 41),
(161, 41), (164, 41), (165, 41), (166, 41), (169, 41), (170, 41), (171, 41), (174, 41), (175, 41),
(176, 41), (182, 3), (188, 42), (188, 43), (188, 44), (189, 42), (189, 43), (189, 44), (190, 42),
(190, 43), (190, 44), (191, 42), (191, 43), (191, 44), (192, 42), (192, 43), (192, 44), (193, 42),
(193, 43), (193, 44), (213, 8), (213, 9), (213, 10), (213, 11), (213, 12), (213, 13), (213, 14),
(213, 15), (213, 16), (213, 17), (213, 18), (213, 19), (213, 20), (213, 21), (213, 22), (213, 23),
(213, 24), (213, 25)],
"Tree Zone Secret Course":
[(10, 24), (11, 24), (12, 24), (17, 23), (39, 24), (40, 24), (41, 24), (42, 24), (45, 24),
(46, 24), (47, 24), (48, 24), (51, 25), (52, 25), (53, 25), (54, 25), (58, 26), (59, 26),
(60, 26), (61, 24), (61, 25), (62, 24), (62, 25), (63, 24), (63, 25), (64, 24), (64, 25),
(67, 25), (68, 26), (69, 27), (70, 27), (73, 26), (74, 27), (75, 27), (76, 27), (80, 23),
(80, 24), (81, 23), (81, 24), (82, 23), (82, 24), (83, 23), (83, 24), (87, 25), (88, 24),
(89, 24), (90, 25), (91, 26), (100, 23), (114, 27), (114, 28), (115, 27), (115, 28), (116, 27),
(116, 28), (117, 27), (117, 28), (118, 27), (118, 28), (119, 27), (119, 28), (120, 27),
(120, 28), (121, 27), (121, 28), (128, 27), (128, 28), (131, 27), (131, 28), (134, 27),
(134, 28), (137, 27), (137, 28), (138, 27), (138, 28), (143, 27), (143, 28), (159, 23)],
"Tree Zone 4":
[(22, 10), (24, 12), (26, 10), (28, 27), (29, 11), (30, 11), (31, 11), (32, 11), (33, 11), (34, 11),
(35, 11), (37, 10), (38, 12), (41, 11), (43, 12), (61, 11), (70, 11), (79, 11), (89, 11), (103, 22),
(103, 25), (103, 28), (105, 22), (105, 25), (105, 28), (107, 22), (107, 25), (107, 28), (109, 22),
(109, 25), (109, 28), (111, 22), (111, 25), (111, 28), (113, 22), (113, 25), (113, 28), (115, 22),
(115, 25), (115, 28), (117, 22), (117, 25), (117, 28), (122, 22), (122, 25), (122, 28), (124, 22),
(124, 25), (124, 28), (126, 22), (126, 25), (126, 28), (128, 22), (128, 25), (128, 28), (130, 22),
(130, 25), (130, 28), (132, 22), (132, 25), (132, 28), (134, 22), (134, 25), (134, 28), (136, 22),
(136, 25), (136, 28), (171, 10), (196, 26), (196, 29), (197, 26), (197, 29), (198, 26), (198, 29),
(199, 26), (199, 29), (200, 26), (200, 29)],
"Tree Zone 3":
[(18, 11), (18, 12), (19, 11), (19, 12), (20, 11), (20, 12), (21, 11), (21, 12), (22, 11), (22, 12),
(26, 40), (27, 11), (27, 12), (28, 11), (28, 12), (29, 11), (29, 12), (30, 11), (30, 12), (31, 11),
(31, 12), (48, 41), (49, 41), (50, 41), (51, 41), (61, 25), (77, 24)],
"Tree Zone 5":
[(23, 41), (84, 39), (85, 39), (116, 42), (123, 39), (132, 39), (134, 36), (134, 39), (134, 43),
(134, 44), (135, 43), (135, 44), (136, 36), (136, 39), (136, 43), (136, 44), (137, 43), (137, 44),
(138, 36), (138, 39), (138, 43), (138, 44), (139, 43), (139, 44), (140, 36), (140, 39), (140, 43),
(140, 44), (141, 43), (141, 44), (142, 36), (142, 39), (142, 43), (142, 44), (144, 36), (144, 39),
(146, 36), (146, 39)],
"Scenic Course":
[(24, 28), (39, 28), (54, 28), (72, 28), (87, 28), (103, 28), (117, 28)],
"Hippo Zone":
[(2, 20), (3, 3), (15, 26), (16, 26), (17, 26), (28, 4), (28, 7), (28, 10), (28, 13), (29, 4),
(29, 7), (29, 10), (29, 13), (29, 21), (30, 4), (30, 7), (30, 10), (30, 13), (32, 15), (33, 15),
(34, 15), (35, 15), (36, 15), (37, 15), (41, 12), (41, 13), (42, 11), (43, 10), (44, 10), (45, 10),
(46, 11), (47, 12), (47, 13), (48, 14), (49, 15), (50, 15), (51, 15), (52, 14), (53, 12), (53, 13),
(54, 11), (55, 10), (56, 10), (57, 10), (58, 11), (59, 12), (59, 13), (60, 14), (61, 15), (62, 15),
(63, 15), (64, 14), (65, 12), (65, 13), (66, 11), (67, 10), (68, 10), (69, 10), (70, 11), (71, 12),
(71, 13), (72, 14), (73, 15), (74, 15), (75, 15), (76, 14), (77, 12), (77, 13), (84, 11), (85, 11),
(85, 22), (86, 22), (91, 6), (92, 6), (92, 11), (93, 6), (93, 11), (94, 11), (95, 16), (96, 12),
(96, 16), (97, 8), (97, 12), (97, 16), (98, 8), (98, 12), (99, 8), (112, 6), (112, 7), (112, 12),
(112, 13), (113, 2), (113, 5), (113, 8), (113, 11), (113, 14), (113, 17), (114, 2), (114, 5),
(114, 8), (114, 11), (114, 14), (114, 17), (115, 3), (115, 4), (115, 9), (115, 10), (115, 15),
(115, 16), (124, 3), (124, 4), (124, 9), (124, 10), (124, 15), (124, 16), (125, 2), (125, 5),
(125, 8), (125, 11), (125, 14), (125, 17), (126, 2), (126, 5), (126, 8), (126, 11), (126, 14),
(126, 17), (127, 6), (127, 7), (127, 12), (127, 13), (129, 13), (130, 13), (131, 13), (132, 13),
(132, 22), (133, 13), (134, 13), (135, 13), (136, 13), (136, 21), (137, 13), (138, 13), (139, 13),
(139, 22), (140, 13), (141, 13), (142, 13), (154, 7), (155, 7), (156, 7), (157, 10), (158, 10),
(159, 10), (162, 15), (162, 16), (162, 17), (164, 15), (164, 16), (164, 17), (166, 15), (166, 16),
(166, 17), (168, 15), (168, 16), (168, 17), (170, 15), (170, 16), (170, 17), (172, 15), (172, 16),
(172, 17), (174, 15), (174, 16), (174, 17), (176, 15), (176, 16), (176, 17)],
"Space Zone 1":
[(38, 26), (45, 25), (46, 25), (47, 25), (57, 24), (58, 24), (59, 24), (60, 19), (60, 23), (61, 23),
(62, 23), (63, 23), (75, 24), (89, 16), (89, 17), (89, 18), (89, 19), (90, 16), (90, 17), (90, 18),
(90, 19), (91, 16), (91, 17), (91, 18), (91, 19), (92, 16), (92, 17), (92, 18), (92, 19), (93, 16),
(93, 17), (93, 18), (93, 19), (104, 22), (105, 22), (114, 22), (115, 22), (125, 10), (126, 9),
(127, 8), (128, 8), (129, 8), (130, 8), (131, 8), (132, 9), (133, 10), (136, 10), (137, 9),
(138, 8), (139, 8), (140, 8), (141, 8), (142, 8), (143, 9), (144, 10), (147, 10), (148, 9),
(149, 8), (150, 8), (151, 8), (152, 8), (153, 8), (154, 9), (155, 10), (155, 18), (155, 19),
(155, 20), (156, 17), (156, 18), (156, 19), (156, 20), (156, 21), (157, 16), (157, 17), (157, 18),
(157, 19), (157, 20), (157, 21), (157, 22), (158, 10), (158, 16), (158, 17), (158, 18), (158, 19),
(158, 20), (158, 21), (158, 22), (159, 9), (159, 16), (159, 17), (159, 18), (159, 19), (159, 20),
(159, 21), (159, 22), (160, 8), (160, 16), (160, 17), (160, 18), (160, 19), (160, 20), (160, 21),
(160, 22), (161, 8), (161, 16), (161, 17), (161, 18), (161, 19), (161, 20), (161, 21), (161, 22),
(162, 8), (162, 17), (162, 18), (162, 19), (162, 20), (162, 21), (163, 8), (163, 18), (163, 19),
(163, 20), (164, 8), (165, 9), (166, 10), (168, 10), (169, 9), (170, 8), (171, 8), (172, 8),
(173, 8), (174, 8), (175, 9), (176, 10)],
"Space Zone Secret Course":
[(16, 22), (16, 23), (16, 24), (18, 21), (18, 22), (18, 23), (20, 21), (20, 22), (20, 23),
(22, 20), (22, 21), (22, 22), (24, 19), (24, 20), (24, 21), (26, 18), (26, 19), (26, 20),
(28, 18), (28, 19), (28, 20), (30, 17), (30, 18), (30, 19), (36, 15), (36, 16), (36, 17),
(38, 14), (38, 15), (38, 16), (40, 13), (40, 14), (40, 15), (40, 24), (41, 24), (42, 13),
(42, 14), (42, 15), (44, 12), (44, 13), (44, 14), (46, 12), (46, 13), (46, 14), (48, 12),
(48, 13), (48, 14), (50, 11), (50, 12), (50, 13), (50, 27), (51, 27), (52, 10), (52, 11),
(52, 12), (52, 27), (53, 27), (54, 27), (58, 11), (58, 12), (58, 13), (60, 12), (60, 13),
(60, 14), (62, 12), (62, 13), (62, 14), (64, 12), (64, 13), (64, 14), (66, 13), (66, 14),
(66, 15), (68, 13), (68, 14), (68, 15), (70, 14), (70, 15), (70, 16), (72, 15), (72, 16),
(72, 17), (74, 16), (74, 17), (74, 18), (80, 18), (80, 19), (80, 20), (82, 19), (82, 20),
(82, 21), (84, 19), (84, 20), (84, 21), (86, 20), (86, 21), (86, 22), (88, 21), (88, 22),
(88, 23)],
"Space Zone 2":
[(11, 13), (12, 13), (13, 13), (20, 8), (21, 8), (22, 8), (25, 5), (26, 5), (27, 5), (33, 6),
(34, 6), (35, 6), (36, 10), (37, 10), (38, 10), (45, 7), (46, 7), (47, 7), (59, 5), (60, 5),
(61, 5), (64, 3), (93, 8), (94, 8), (95, 8), (96, 11), (97, 11), (98, 11), (100, 6), (101, 6),
(102, 6), (102, 8), (120, 5), (124, 12), (124, 13), (125, 12), (125, 13), (126, 12), (126, 13),
(127, 3), (127, 12), (127, 13), (128, 3), (128, 7), (129, 3), (129, 7), (130, 7), (148, 6),
(148, 7), (148, 8), (149, 5), (149, 6), (149, 7), (149, 8), (149, 9), (150, 5), (150, 6), (150, 7),
(150, 8), (150, 9), (151, 5), (151, 6), (151, 7), (151, 8), (151, 9), (152, 5), (152, 6), (152, 7),
(152, 8), (152, 9), (153, 6), (153, 7), (153, 8), (165, 7), (165, 8), (166, 7), (166, 8), (167, 7),
(167, 8), (168, 7), (168, 8), (169, 7), (169, 8), (170, 7), (170, 8), (171, 7), (171, 8), (181, 9),
(185, 4), (200, 3), (200, 6), (200, 9), (201, 3), (201, 6), (201, 9), (202, 3), (202, 6), (202, 9),
(203, 3), (203, 6), (203, 9), (204, 3), (204, 6), (204, 9), (205, 3), (205, 6), (205, 9), (206, 3),
(206, 6), (206, 9), (207, 3), (207, 6), (207, 9), (208, 3), (208, 6), (208, 9), (209, 3), (209, 6),
(209, 9), (210, 3), (210, 6), (210, 9), (230, 12), (231, 12), (232, 12), (236, 2), (236, 3),
(236, 4), (236, 5), (237, 2), (237, 3), (237, 4), (237, 5), (238, 2), (238, 3), (238, 4), (238, 5),
(248, 10)],
"Turtle Zone 1":
[(22, 34), (27, 37), (28, 37), (29, 37), (30, 37), (31, 37), (32, 37), (33, 37), (34, 37),
(35, 37), (36, 37), (46, 32), (46, 33), (47, 32), (47, 33), (50, 32), (50, 33), (51, 32),
(51, 33), (54, 32), (54, 33), (55, 32), (55, 33), (56, 33), (57, 33), (58, 32), (58, 33),
(59, 32), (59, 33), (62, 32), (62, 33), (63, 32), (63, 33), (66, 32), (66, 33), (67, 32),
(67, 33), (73, 43), (74, 43), (75, 43), (77, 41), (78, 41), (79, 41), (81, 40), (82, 40),
(83, 40), (85, 41), (86, 41), (87, 41), (122, 36), (123, 36), (124, 36), (125, 36), (126, 36),
(127, 36), (130, 36), (131, 36), (132, 36), (133, 36), (134, 36), (135, 36), (136, 36), (137, 36),
(138, 36), (139, 36), (140, 36), (141, 36), (143, 34), (163, 36), (164, 36), (166, 36), (167, 36),
(169, 36), (170, 36), (180, 37), (181, 37), (182, 37), (183, 37), (184, 37), (185, 37), (188, 44),
(189, 44)],
"Turtle Zone 2":
[(6, 34), (11, 34), (15, 43), (48, 36), (51, 28), (56, 35), (57, 35), (59, 42), (61, 20), (62, 20),
(62, 35), (63, 20), (63, 35), (64, 20), (65, 20), (67, 35), (68, 35), (72, 39), (79, 34),
(82, 35), (87, 42), (96, 43), (105, 43), (107, 43), (109, 43), (118, 28), (121, 28), (139, 39),
(142, 39)],
"Turtle Zone Secret Course":
[(19, 27), (39, 27), (39, 28), (40, 26), (40, 27), (41, 25), (41, 27), (42, 25), (42, 27),
(43, 26), (43, 27), (44, 27), (44, 28), (48, 25), (48, 26), (48, 27), (48, 28), (49, 25),
(49, 27), (50, 25), (50, 27), (51, 25), (51, 27), (52, 26), (52, 28), (53, 27), (61, 25),
(61, 28), (62, 25), (62, 26), (62, 27), (62, 28), (63, 25), (63, 28), (64, 26), (73, 26),
(73, 27), (74, 25), (74, 28), (75, 25), (75, 28), (76, 25), (76, 28), (77, 26), (77, 27),
(82, 25), (82, 26), (82, 27), (82, 28), (83, 28), (84, 28), (85, 28), (87, 27), (89, 27),
(89, 28), (90, 26), (90, 27), (91, 25), (91, 27), (92, 25), (92, 27), (93, 26), (93, 27),
(94, 27), (94, 28), (98, 24), (98, 25), (98, 26), (98, 27), (99, 25), (100, 26), (101, 27),
(102, 24), (102, 25), (102, 26), (102, 27), (108, 24), (108, 25), (108, 26), (108, 27),
(109, 24), (109, 27), (110, 24), (110, 27), (111, 24), (111, 27), (112, 25), (112, 26),
(116, 24), (116, 27), (117, 23), (117, 26), (117, 27), (118, 23), (118, 25), (118, 27),
(119, 23), (119, 25), (119, 27), (120, 24), (120, 27), (121, 28), (122, 28), (123, 28)],
"Turtle Zone 3":
[(16, 25), (17, 25), (18, 25), (19, 25), (20, 25), (21, 25), (22, 25), (23, 25), (24, 25),
(35, 24), (36, 24), (37, 24), (38, 24), (39, 24), (40, 24), (41, 24), (42, 24), (43, 24),
(75, 28), (75, 29), (76, 28), (76, 29), (81, 28), (81, 29), (82, 28), (82, 29), (92, 26),
(93, 26), (94, 26), (98, 26), (99, 26), (100, 26), (123, 26), (124, 26), (126, 26), (127, 26),
(129, 26), (130, 26), (146, 22), (146, 29), (147, 22), (147, 29), (148, 22), (150, 22), (151, 22),
(152, 23), (152, 29), (153, 29), (154, 22), (155, 22), (156, 22), (158, 29), (159, 29), (161, 22),
(162, 22), (163, 22), (165, 22), (166, 22), (167, 22), (169, 22), (170, 22), (171, 22)],
"Mario Zone 1":
[(18, 44), (47, 36), (47, 37), (47, 38), (47, 39), (49, 36), (49, 37), (49, 38), (50, 36), (50, 37),
(50, 38), (52, 36), (52, 37), (52, 38), (53, 36), (53, 37), (53, 38), (60, 35), (60, 36), (60, 37),
(61, 35), (61, 36), (61, 37), (64, 35), (64, 36), (64, 37), (65, 35), (65, 36), (65, 37), (71, 36),
(78, 36), (78, 37), (78, 38), (98, 38), (145, 42), (146, 22), (146, 23), (146, 25), (146, 26),
(146, 42), (147, 22), (147, 23), (147, 25), (147, 26), (147, 30), (147, 31), (147, 32), (147, 42),
(148, 22), (148, 23), (148, 25), (148, 30), (148, 31), (148, 32), (148, 42), (149, 21), (149, 22),
(149, 23), (149, 24), (149, 30), (149, 31), (149, 42), (150, 21), (150, 22), (150, 23), (150, 24),
(150, 26), (150, 27), (150, 28), (150, 30), (150, 31), (150, 42), (151, 27), (151, 28), (151, 30),
(151, 31), (151, 42), (152, 27), (152, 29), (152, 30), (152, 31), (152, 42), (153, 27), (153, 29),
(153, 30), (153, 42), (154, 27), (154, 29), (154, 30), (164, 20), (167, 21), (167, 26), (167, 34),
(168, 21), (168, 25), (168, 27), (168, 33), (168, 35), (169, 20), (169, 24), (169, 28), (169, 33),
(169, 35), (170, 20), (170, 23), (170, 29), (170, 32), (170, 35), (171, 20), (171, 23), (171, 29),
(171, 32), (171, 36), (171, 37), (172, 21), (172, 22), (172, 30), (172, 31)],
"Mario Zone 2":
[(25, 24), (25, 27), (26, 24), (26, 27), (27, 24), (27, 27), (81, 27), (112, 24), (113, 24),
(114, 24), (115, 24), (116, 24), (117, 24), (118, 24), (121, 24), (122, 24), (123, 24), (124, 24),
(125, 24), (126, 24), (127, 24), (138, 26), (139, 26), (140, 24), (140, 28), (141, 24), (141, 28),
(144, 26), (145, 26), (146, 24), (146, 28), (147, 28), (151, 26), (152, 24), (152, 28), (153, 24),
(153, 28), (156, 26), (157, 26), (158, 24), (158, 28), (159, 24), (159, 28), (162, 26), (163, 26),
(164, 28), (165, 28)],
"Mario Zone 3":
[(8, 28), (11, 28), (14, 28), (17, 28), (20, 28), (23, 28), (54, 25), (100, 27), (109, 18),
(109, 19), (110, 18), (110, 19), (111, 17), (111, 18), (111, 19), (112, 17), (112, 18), (112, 19),
(127, 17), (127, 18), (127, 19), (128, 17), (128, 18), (128, 19), (129, 18), (129, 19), (130, 18),
(130, 19), (130, 20), (131, 18), (131, 19), (131, 20), (132, 18), (132, 19), (132, 20), (133, 18),
(133, 19), (133, 20), (133, 27), (134, 18), (134, 19), (134, 20), (157, 28), (158, 28), (159, 28),
(160, 28), (161, 28), (168, 28), (169, 28), (170, 28), (171, 28), (172, 28), (189, 44), (199, 28),
(200, 28), (201, 28), (202, 28), (203, 28), (214, 27), (217, 27), (220, 27), (223, 27)],
"Mario Zone 4":
[(20, 25), (114, 24), (114, 25), (114, 26), (115, 24), (115, 25), (115, 26), (115, 27), (115, 28),
(115, 29), (116, 24), (116, 25), (116, 26), (116, 27), (116, 29), (117, 24), (117, 25), (117, 26),
(117, 27), (117, 28), (117, 29), (118, 24), (118, 25), (118, 26), (118, 27), (118, 28), (118, 29),
(119, 24), (119, 25), (119, 27), (119, 28), (119, 29), (120, 24), (120, 25), (120, 26), (120, 27),
(120, 28), (120, 29), (121, 24), (121, 25), (121, 26), (121, 27), (121, 28), (121, 29), (122, 12),
(122, 24), (122, 25), (122, 26), (122, 27), (122, 29), (123, 12), (123, 24), (123, 25), (123, 26),
(123, 27), (123, 28), (123, 29), (124, 12), (124, 24), (124, 25), (124, 26), (124, 27), (124, 28),
(124, 29), (125, 12), (179, 12)],
"Pumpkin Zone 1":
[(23, 12), (55, 24), (55, 26), (56, 27), (57, 24), (57, 26), (63, 24), (63, 26), (64, 27),
(65, 24), (65, 26), (71, 24), (71, 26), (72, 27), (73, 24), (73, 26), (79, 24), (79, 26),
(80, 27), (81, 24), (81, 26), (86, 25), (86, 27), (92, 4), (93, 27), (95, 25), (95, 27), (98, 4),
(102, 26), (102, 28), (104, 4), (104, 26), (104, 28), (165, 14), (166, 15), (171, 20), (172, 21),
(173, 22), (175, 24), (176, 25), (177, 26), (179, 28), (180, 29), (189, 6)],
"Pumpkin Zone 2":
[(34, 26), (40, 21), (41, 21), (42, 21), (43, 21), (48, 20), (49, 20), (50, 20), (50, 41),
(51, 20), (51, 41), (52, 41), (53, 41), (54, 41), (56, 21), (57, 21), (58, 21), (59, 21),
(61, 41), (62, 41), (64, 20), (65, 20), (66, 20), (67, 20), (114, 36), (115, 35), (115, 36),
(116, 34), (116, 35), (116, 36), (132, 20), (132, 21), (132, 22), (132, 23), (132, 24),
(144, 23), (169, 27)],
"Pumpkin Zone 3":
[(18, 26), (20, 26), (22, 26), (24, 26), (26, 26), (31, 18), (32, 18), (33, 18), (34, 18),
(35, 18), (36, 18), (37, 18), (38, 18), (39, 18), (40, 18), (41, 18), (42, 18), (48, 24),
(52, 20), (52, 24), (56, 24), (87, 27), (88, 27), (89, 27), (90, 27), (94, 27), (95, 27),
(96, 27), (97, 27), (101, 27), (102, 27), (103, 27), (104, 27), (104, 42), (108, 27), (109, 27),
(110, 27), (111, 27), (115, 27), (116, 27), (117, 27), (118, 27), (134, 35), (134, 41),
(135, 35), (135, 41), (136, 35), (136, 41), (137, 35), (137, 41), (138, 35), (138, 41),
(139, 35), (139, 41), (140, 41), (225, 38), (226, 37), (227, 36), (227, 37), (227, 38),
(227, 39), (227, 40), (227, 41), (228, 37), (229, 38)],
"Pumpkin Zone Secret Course 1":
[(14, 15), (16, 9), (16, 10), (16, 11), (16, 12), (16, 13), (16, 14), (16, 15), (16, 16),
(17, 9), (17, 10), (17, 11), (17, 12), (17, 13), (17, 14), (17, 15), (17, 16), (18, 9),
(18, 10), (18, 11), (18, 12), (18, 13), (18, 14), (18, 15), (18, 16), (19, 9), (19, 10),
(19, 11), (19, 12), (19, 13), (19, 14), (19, 15), (19, 16), (20, 9), (20, 10), (20, 11),
(20, 12), (20, 13), (20, 14), (20, 15), (20, 16), (21, 9), (21, 10), (21, 11), (21, 12),
(21, 13), (21, 14), (21, 15), (21, 16), (22, 9), (22, 10), (22, 11), (22, 12), (22, 13),
(22, 14), (22, 15), (22, 16), (23, 9), (23, 10), (23, 11), (23, 12), (23, 13), (23, 14),
(23, 15), (23, 16), (24, 9), (24, 10), (24, 11), (24, 12), (24, 13), (24, 14), (24, 15),
(24, 16), (25, 9), (25, 10), (25, 11), (25, 12), (25, 13), (25, 14), (25, 15), (25, 16),
(26, 9), (26, 10), (26, 11), (26, 12), (26, 13), (26, 14), (26, 15), (27, 16), (28, 9),
(28, 10), (28, 11), (28, 12), (28, 13), (28, 14), (28, 15), (28, 16), (29, 9), (29, 10),
(29, 11), (29, 12), (29, 13), (29, 14), (29, 15), (29, 16), (30, 9), (30, 10), (30, 11),
(30, 12), (30, 13), (30, 14), (30, 15), (30, 16), (31, 9), (31, 10), (31, 11), (31, 12),
(31, 13), (31, 14), (31, 15), (31, 16), (32, 9), (32, 10), (32, 11), (32, 12), (32, 13),
(32, 14), (32, 15), (32, 16), (33, 9), (33, 10), (33, 11), (33, 12), (33, 13), (33, 14),
(33, 15), (33, 16), (34, 9), (34, 10), (34, 11), (34, 12), (34, 13), (34, 14), (34, 15),
(34, 16), (35, 9), (35, 10), (35, 11), (35, 12), (35, 13), (35, 14), (35, 15), (35, 16),
(36, 9), (36, 10), (36, 11), (36, 12), (36, 13), (36, 14), (36, 15), (36, 16), (37, 9),
(37, 10), (37, 11), (37, 12), (37, 13), (37, 14), (37, 15), (37, 16), (39, 16), (40, 9),
(40, 10), (40, 11), (40, 12), (40, 13), (40, 14), (40, 15), (40, 16), (41, 9), (41, 10),
(41, 11), (41, 12), (41, 13), (41, 14), (41, 15), (41, 16), (42, 9), (42, 10), (42, 11),
(42, 12), (42, 13), (42, 14), (42, 15), (42, 16), (43, 9), (43, 10), (43, 11), (43, 12),
(43, 13), (43, 14), (43, 15), (43, 16), (44, 9), (44, 10), (44, 11), (44, 12), (44, 13),
(44, 14), (44, 15), (44, 16), (45, 9), (45, 10), (45, 11), (45, 12), (45, 13), (45, 14),
(45, 15), (45, 16), (46, 9), (46, 10), (46, 11), (46, 12), (46, 13), (46, 14), (46, 15),
(46, 16), (47, 9), (47, 10), (47, 11), (47, 12), (47, 13), (47, 14), (47, 15), (47, 16),
(48, 9), (48, 10), (48, 11), (48, 12), (48, 13), (48, 14), (48, 15), (48, 16), (49, 9),
(49, 10), (49, 11), (49, 12), (49, 13), (49, 14), (49, 15), (49, 16), (52, 9), (52, 10),
(52, 11), (52, 12), (52, 13), (52, 14), (52, 15), (52, 16), (53, 9), (53, 10), (53, 11),
(53, 12), (53, 13), (53, 14), (53, 15), (53, 16), (54, 9), (54, 10), (54, 11), (54, 12),
(54, 13), (54, 14), (54, 15), (54, 16), (55, 9), (55, 10), (55, 11), (55, 12), (55, 13),
(55, 14), (55, 15), (55, 16), (56, 9), (56, 10), (56, 11), (56, 12), (56, 13), (56, 14),
(56, 15), (56, 16), (57, 9), (57, 10), (57, 11), (57, 12), (57, 13), (57, 14), (57, 15),
(57, 16), (58, 9), (58, 10), (58, 11), (58, 12), (58, 13), (58, 14), (58, 15), (58, 16),
(59, 9), (59, 10), (59, 11), (59, 12), (59, 13), (59, 14), (59, 15), (59, 16), (60, 9),
(60, 10), (60, 11), (60, 12), (60, 13), (60, 14), (60, 15), (60, 16), (61, 9), (61, 10),
(61, 11), (61, 12), (61, 13), (61, 14), (61, 15), (61, 16), (64, 9), (64, 10), (64, 11),
(64, 12), (64, 13), (64, 14), (64, 15), (64, 16), (65, 9), (65, 10), (65, 11), (65, 12),
(65, 13), (65, 14), (65, 15), (65, 16), (66, 9), (66, 10), (66, 11), (66, 12), (66, 13),
(66, 14), (66, 15), (66, 16), (67, 9), (67, 10), (67, 11), (67, 12), (67, 13), (67, 14),
(67, 15), (67, 16), (68, 9), (68, 10), (68, 11), (68, 12), (68, 13), (68, 14), (68, 15),
(68, 16), (69, 9), (69, 10), (69, 11), (69, 12), (69, 13), (69, 14), (69, 15), (69, 16),
(70, 9), (70, 10), (70, 11), (70, 12), (70, 13), (70, 14), (70, 15), (70, 16), (71, 9),
(71, 10), (71, 11), (71, 12), (71, 13), (71, 14), (71, 15), (71, 16), (72, 9), (72, 10),
(72, 11), (72, 12), (72, 13), (72, 14), (72, 15), (72, 16), (73, 9), (73, 10), (73, 11),
(73, 12), (73, 13), (73, 14), (73, 15), (73, 16)],
"Pumpkin Zone Secret Course 2":
[(12, 6), (72, 7), (73, 7), (80, 7), (81, 7), (85, 8), (90, 10), (91, 10), (94, 10),
(95, 10), (98, 9), (99, 9), (102, 9), (103, 9)],
"Pumpkin Zone 4":
[(18, 28), (19, 28), (20, 28), (21, 28), (83, 37), (83, 38), (84, 37), (84, 38), (85, 37),
(85, 38), (85, 39), (86, 37), (87, 37), (87, 40), (88, 37), (88, 38), (88, 39), (88, 40),
(89, 37), (89, 38), (89, 39), (89, 40), (90, 37), (90, 38), (91, 37), (91, 38), (92, 37),
(92, 38), (92, 39), (92, 40), (93, 23), (93, 37), (93, 40), (94, 23), (94, 37), (94, 40),
(103, 23), (104, 23), (113, 23), (114, 23), (169, 30), (170, 28), (170, 30), (171, 26),
(171, 28), (171, 30), (172, 24), (172, 26), (172, 28), (172, 30), (173, 24), (173, 26),
(173, 28), (173, 30), (174, 26), (174, 28), (174, 30), (175, 28), (175, 30), (176, 30),
(198, 37), (198, 38), (199, 37), (199, 38), (204, 37), (204, 38), (205, 37), (205, 38),
(210, 37), (210, 38), (211, 37), (211, 38), (216, 37), (216, 38), (217, 37), (217, 38)],
"Macro Zone 1":
[(22, 32), (22, 33), (22, 34), (23, 20), (23, 21), (23, 22), (23, 38), (23, 39), (23, 40), (24, 26),
(24, 27), (24, 28), (39, 42), (40, 41), (41, 40), (42, 39), (49, 43), (62, 42), (62, 43), (62, 44),
(68, 42), (68, 43), (68, 44), (75, 42), (75, 43), (75, 44), (84, 40), (84, 41), (84, 42), (87, 39),
(89, 42), (89, 43), (89, 44), (107, 42), (108, 42), (109, 42), (118, 42), (119, 42), (120, 42),
(121, 42), (122, 42), (128, 42), (128, 43), (130, 42), (130, 43), (134, 42), (134, 43), (140, 42),
(141, 42), (142, 42), (143, 42), (144, 42), (154, 42), (155, 42), (156, 42), (163, 22), (163, 23),
(164, 21), (164, 22), (164, 23), (165, 22), (165, 23), (166, 21), (166, 22), (166, 23), (167, 22),
(167, 23), (168, 21), (168, 22), (168, 23), (169, 22), (169, 23), (170, 21), (170, 22), (170, 23),
(171, 22), (171, 23), (177, 40), (182, 40), (189, 41), (189, 42), (189, 43), (189, 44), (189, 45),
(205, 46), (206, 46), (208, 37), (209, 37), (212, 41), (213, 41), (214, 41), (215, 41), (216, 41),
(220, 37), (221, 37), (224, 46), (225, 46), (234, 43), (246, 38), (246, 39), (246, 40), (246, 41),
(246, 42), (246, 43)],
"Macro Zone 2":
[(18, 28), (19, 27), (22, 28), (23, 27), (25, 26), (27, 27), (28, 27), (31, 27), (32, 27), (41, 29),
(42, 29), (43, 29), (55, 29), (57, 29), (60, 29), (62, 29), (69, 27), (70, 27), (71, 27), (74, 27),
(75, 27), (76, 27), (79, 27), (80, 27), (81, 27), (84, 27), (85, 27), (86, 27), (99, 40),
(137, 37), (180, 40), (181, 8), (182, 8), (183, 8), (184, 8), (185, 8), (186, 8), (187, 8),
(188, 8), (189, 8), (190, 8), (191, 8), (192, 8), (193, 8), (194, 8), (195, 8), (196, 8), (197, 8),
(198, 8), (199, 8), (200, 8), (201, 8), (202, 8), (204, 8), (205, 8), (206, 8), (207, 8), (208, 8),
(209, 8), (210, 8), (211, 8), (212, 8), (213, 8), (215, 8), (216, 8), (217, 8), (217, 11),
(218, 8), (218, 9), (218, 10), (218, 11), (218, 12), (219, 11)],
"Macro Zone 3":
[(24, 23), (37, 28), (38, 28), (39, 28), (40, 28), (57, 30), (58, 30), (59, 30), (65, 17), (65, 18),
(65, 19), (66, 17), (66, 18), (66, 19), (67, 17), (67, 18), (67, 19), (68, 17), (68, 18), (68, 19),
(69, 17), (69, 18), (69, 19), (70, 17), (70, 18), (70, 19), (73, 17), (73, 18), (73, 19), (74, 17),
(74, 18), (74, 19), (75, 17), (75, 18), (75, 19), (76, 17), (76, 18), (76, 19), (77, 17), (77, 18),
(77, 19), (78, 17), (78, 18), (78, 19), (85, 43), (95, 17), (95, 18), (95, 19), (95, 20), (96, 17),
(96, 18), (96, 19), (96, 20), (97, 17), (97, 18), (97, 19), (97, 20), (98, 17), (98, 18), (98, 19),
(98, 20), (100, 17), (100, 18), (100, 19), (100, 20), (101, 17), (101, 18), (101, 19), (101, 20),
(103, 42), (104, 42), (105, 42), (106, 42), (107, 42), (116, 42), (117, 42), (118, 42), (119, 42),
(120, 42), (121, 42), (122, 42), (129, 19), (131, 42), (132, 42), (133, 42), (134, 42), (135, 42),
(136, 42), (165, 21), (165, 22), (166, 21), (166, 22), (171, 21), (171, 22), (172, 21), (172, 22),
(176, 20), (176, 21), (176, 22), (179, 20), (179, 21), (179, 22), (183, 21), (183, 22), (184, 21),
(184, 22), (194, 27), (194, 28), (197, 27), (197, 28), (200, 27), (200, 28), (203, 25), (203, 27),
(203, 28), (205, 18), (205, 19), (206, 18), (206, 19)],
"Macro Zone 4":
[(16, 28), (34, 28), (39, 28), (39, 29), (39, 30), (40, 28), (40, 29), (40, 30), (41, 28), (41, 29),
(41, 30), (62, 29), (63, 29), (64, 29), (65, 29), (66, 29), (67, 29), (68, 29), (69, 29), (81, 17),
(81, 18), (82, 17), (82, 18), (83, 17), (83, 18), (84, 17), (84, 18), (85, 17), (85, 18), (86, 17),
(86, 18), (87, 17), (87, 18), (87, 28), (88, 17), (88, 18), (114, 28), (144, 22), (146, 27),
(146, 28), (147, 27), (147, 28), (148, 27), (148, 28), (149, 27), (149, 28), (150, 27), (150, 28),
(151, 27), (151, 28), (152, 27), (152, 28), (153, 27), (153, 28), (154, 27), (154, 28), (155, 27),
(155, 28), (156, 27), (156, 28), (157, 27), (157, 28), (158, 27), (158, 28)],
"Macro Zone Secret Course":
[(21, 24), (70, 27), (70, 28), (71, 27), (71, 28), (72, 27), (72, 28), (73, 27), (73, 28),
(74, 27), (74, 28), (75, 27), (75, 28), (76, 24), (76, 25), (76, 26), (76, 27), (76, 28),
(77, 24), (77, 25), (77, 26), (77, 27), (77, 28), (78, 24), (78, 25), (78, 26), (78, 27),
(78, 28), (79, 24), (79, 25), (79, 26), (79, 27), (80, 25), (80, 26), (81, 25), (81, 26),
(88, 25), (108, 30)],
"Mario's Castle":
[(7, 25), (160, 44), (167, 28), (247, 26)],
}
powerup_coords = {
"Mushroom Zone": [(42, 28), (151, 28), (152, 28), (188, 28)],
"Scenic Course": [(39, 28), (72, 28), (117, 28)],
"Tree Zone 1": [(119, 28), (152, 28)],
"Tree Zone 2": [(43, 10), (61, 9), (51, 28), (130, 7), (182, 3), (136, 43)],
"Tree Zone Secret Course": [(17, 23), (100, 23), (159, 23)],
"Tree Zone 3": [(26, 40), (77, 24)],
"Tree Zone 4": [(28, 27), (105, 25), (136, 22), (171, 10)],
"Tree Zone 5": [(123, 39), (138, 39), (146, 36)],
"Pumpkin Zone 1": [(23, 12), (72, 27), (98, 4), (189, 6)],
"Pumpkin Zone 2": [(144, 23)],
"Pumpkin Zone Secret Course 1": [(14, 15)],
"Pumpkin Zone 3": [(52, 20), (104, 42), (139, 35), (140, 41)],
"Pumpkin Zone Secret Course 2": [(12, 6), (85, 8)],
"Pumpkin Zone 4": [(83, 38), (94, 40), (104, 23)],
"Mario Zone 1": [(18, 44), (98, 38), (145, 42), (164, 20)],
"Mario Zone 2": [(81, 27)],
"Mario Zone 3": [(54, 25), (100, 27), (134, 18), (189, 44), (214, 27)],
"Mario Zone 4": [(20, 25), (124, 12), (179, 12)],
"Turtle Zone 1": [(22, 34), (56, 33), (57, 33), (143, 34), (189, 44)],
"Turtle Zone 2": [(82, 35), (139, 39), ],
"Turtle Zone Secret Course": [(19, 27), (53, 27), (64, 26), (87, 27), (121, 28), (122, 28), (123, 28)],
"Turtle Zone 3": [(39, 24), (94, 26), (152, 23)],
"Hippo Zone": [(3, 3), (2, 20), (15, 26), (16, 26), (29, 21), (86, 22), (137, 13)],
"Space Zone 1": [(75, 24), (114, 22)],
# "Space Zone Secret Course": [],
"Space Zone 2": [(64, 3), (102, 8), (120, 5), (207, 6), (210, 9), (248, 10)],
"Macro Zone 1": [(49, 43), (87, 39), (177, 40), (164, 21), (166, 21), (170, 21), (234, 43)],
"Macro Zone 2": [(25, 26), (99, 40), (137, 37), (180, 40)],
"Macro Zone 3": [(24, 23), (85, 43), (129, 19), (203, 25)],
"Macro Zone 4": [(16, 28), (87, 28), (144, 22)],
"Macro Zone Secret Course": [(21, 24), (88, 25), (108, 30)],
"Mario's Castle": [(7, 25), (160, 44), (167, 28), (247, 26)]
}
for zone, coords_list in powerup_coords.items():
for coords in coords_list:
coins_coords[zone].remove(coords)
location_name_to_id = {location_name: ID for ID, location_name in enumerate(locations, START_IDS)}
loc_id = START_IDS + len(locations)
for level, coin_coords in coins_coords.items():
for i in range(1, len(coin_coords) + 1):
location_name_to_id[f"{level} - {i} Coin{'s' if i > 1 else ''}"] = loc_id
loc_id += 1
# eligible_levels = [0, 1, 2, 3, 5, 8, 9, 11, 13, 14, 16, 19, 20, 22, 23, 25, 30, 31]
level_id_to_name = {
0: "Mushroom Zone", 25: "Scenic Course", 1: "Tree Zone 1", 2: "Tree Zone 2", 4: "Tree Zone 3", 3: "Tree Zone 4",
5: "Tree Zone 5", 29: "Tree Zone Secret Course", 17: "Hippo Zone", 18: "Space Zone 1",
28: "Space Zone Secret Course", 19: "Space Zone 2", 20: "Macro Zone 1", 21: "Macro Zone 2", 22: "Macro Zone 3",
23: "Macro Zone 4", 30: "Macro Zone Secret Course", 6: "Pumpkin Zone 1", 7: "Pumpkin Zone 2",
8: "Pumpkin Zone 3", 9: "Pumpkin Zone 4", 27: "Pumpkin Zone Secret Course 1", 31: "Pumpkin Zone Secret Course 2",
10: "Mario Zone 1", 11: "Mario Zone 2", 12: "Mario Zone 3", 13: "Mario Zone 4", 14: "Turtle Zone 1",
15: "Turtle Zone 2", 16: "Turtle Zone 3", 26: "Turtle Zone Secret Course", 24: "Mario's Castle"
}
level_name_to_id = {name: level_id for level_id, name in level_id_to_name.items()}
auto_scroll_max = {
"Mushroom Zone": 84,
"Hippo Zone": 160,
"Tree Zone 1": 87,
"Tree Zone 2": 68,
"Tree Zone 3": 4,
"Tree Zone 4": 28,
"Tree Zone 5": 22,
"Space Zone 1": 72,
"Space Zone 2": 113,
"Space Zone Secret Course": 96,
"Macro Zone 1": 74,
"Macro Zone 2": 27,
"Macro Zone 3": 63,
"Macro Zone 4": 59,
"Pumpkin Zone 1": (0, 12),
"Pumpkin Zone 2": 23,
"Pumpkin Zone 3": 50,
"Pumpkin Zone 4": 45,
"Pumpkin Zone Secret Course 1": 172,
"Mario Zone 1": 68,
"Mario Zone 3": 29,
"Mario Zone 4": 60,
"Turtle Zone 1": 66,
"Turtle Zone 2": 8,
}

608
worlds/marioland2/logic.py Normal file
View File

@@ -0,0 +1,608 @@
from .locations import level_name_to_id
def is_auto_scroll(state, player, level):
level_id = level_name_to_id[level]
if state.has_any(["Cancel Auto Scroll", f"Cancel Auto Scroll - {level}"], player):
return False
return state.multiworld.worlds[player].auto_scroll_levels[level_id] > 0
def has_pipe_right(state, player):
return state.has_any(["Pipe Traversal - Right", "Pipe Traversal"], player)
def has_pipe_left(state, player):
return state.has_any(["Pipe Traversal - Left", "Pipe Traversal"], player)
def has_pipe_down(state, player):
return state.has_any(["Pipe Traversal - Down", "Pipe Traversal"], player)
def has_pipe_up(state, player):
return state.has_any(["Pipe Traversal - Up", "Pipe Traversal"], player)
def has_level_progression(state, item, player, count=1):
return state.count(item, player) + (state.count(item + " x2", player) * 2) >= count
def mushroom_zone_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Mushroom Zone")
reachable_coins = 38
if state.has_any(["Mushroom", "Fire Flower"], player) or not auto_scroll:
# Was able to get all but 1, being lenient.
reachable_coins += 2
if has_pipe_down(state, player):
# There's 24 in each of the underground sections.
# The first one requires missing some question mark blocks if auto scrolling (the last +4).
# If you go in the second without pipe up, you can get everything except the last 5 plus the ones in the first
# underground section.
reachable_coins += 19
if has_pipe_up(state, player) or not auto_scroll:
reachable_coins += 5
if has_pipe_up(state, player):
reachable_coins += 20
if not auto_scroll:
reachable_coins += 4
return coins <= reachable_coins
def tree_zone_1_coins(state, player, coins):
return coins <= 87 or not is_auto_scroll(state, player, "Tree Zone 1")
def tree_zone_2_normal_exit(state, player):
return has_pipe_right(state, player) or state.has("Tree Zone 2 Midway Bell", player)
def tree_zone_2_secret_exit(state, player):
return has_pipe_right(state, player) and state.has("Carrot", player)
def tree_zone_2_midway_bell(state, player):
return has_pipe_right(state, player) or state.has("Tree Zone 2 Midway Bell", player)
def tree_zone_2_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Tree Zone 2")
reachable_coins = 18
if has_pipe_right(state, player):
reachable_coins += 38
if state.has("Carrot", player):
reachable_coins += 12
if not auto_scroll:
reachable_coins += 30
elif state.has("Tree Zone 2 Midway Bell", player):
reachable_coins = 30
if not auto_scroll:
reachable_coins += 8
return coins <= reachable_coins
def tree_zone_3_normal_exit(state, player):
return not is_auto_scroll(state, player, "Tree Zone 3")
def tree_zone_3_coins(state, player, coins):
if is_auto_scroll(state, player, "Tree Zone 3"):
return coins <= 4
if coins <= 19:
return True
elif state.has_any(["Mushroom", "Fire Flower"], player) and coins <= 21:
return True
return state.has("Carrot", player)
def tree_zone_4_normal_exit(state, player):
return has_pipe_down(state, player) and tree_zone_4_midway_bell(state, player)
def tree_zone_4_midway_bell(state, player):
return ((has_pipe_right(state, player) and has_pipe_up(state, player))
or state.has("Tree Zone 4 Midway Bell", player))
def tree_zone_4_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Tree Zone 4")
reachable_coins = 0
if has_pipe_up(state, player):
reachable_coins += 14
if has_pipe_right(state, player):
reachable_coins += 4
if has_pipe_down(state, player):
reachable_coins += 10
if not auto_scroll:
reachable_coins += 46
elif state.has("Tree Zone 4 Midway Bell", player):
if not auto_scroll:
if has_pipe_left(state, player):
reachable_coins += 18
if has_pipe_down(state, player):
reachable_coins += 10
if has_pipe_up(state, player):
reachable_coins += 46
elif has_pipe_down(state, player):
reachable_coins += 10
return coins <= reachable_coins
def tree_zone_5_boss(state, player):
return has_pipe_right(state, player) and (has_pipe_up(state, player) or state.has("Carrot", player))
def tree_zone_5_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Tree Zone 5")
reachable_coins = 0
# Not actually sure if these platforms can be randomized / can make the coin blocks unreachable from below
if ((not state.multiworld.worlds[player].options.randomize_platforms)
or state.has_any(["Mushroom", "Fire Flower"], player)):
reachable_coins += 2
if state.has_any(["Mushroom", "Fire Flower"], player):
reachable_coins += 2
if state.has("Carrot", player):
reachable_coins += 18
if has_pipe_up(state, player) and not auto_scroll:
reachable_coins += 13
elif has_pipe_up(state, player):
reachable_coins += 13
return coins <= reachable_coins
def pumpkin_zone_1_normal_exit(state, player):
return pumpkin_zone_1_midway_bell(state, player)
def pumpkin_zone_1_midway_bell(state, player):
return ((has_pipe_down(state, player) and not is_auto_scroll(state, player, "Pumpkin Zone 1"))
or state.has("Pumpkin Zone 1 Midway Bell", player))
def pumpkin_zone_1_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Pumpkin Zone 1")
if auto_scroll:
return coins <= 12 and state.has("Pumpkin Zone 1 Midway Bell", player)
reachable_coins = 0
if state.has("Pumpkin Zone 1 Midway Bell", player) or has_pipe_down(state, player):
reachable_coins += 38
if has_pipe_up(state, player):
reachable_coins += 2
return coins <= reachable_coins
def pumpkin_zone_2_normal_exit(state, player):
return has_pipe_down(state, player) and has_pipe_up(state, player) and has_pipe_right(state, player) and state.has(
"Water Physics", player) and not is_auto_scroll(state, player, "Pumpkin Zone 2")
def pumpkin_zone_2_secret_exit(state, player):
return pumpkin_zone_2_normal_exit(state, player) and state.has_any(["Mushroom", "Fire Flower"], player)
def pumpkin_zone_2_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Pumpkin Zone 2")
reachable_coins = 17
if has_pipe_down(state, player):
if not auto_scroll:
reachable_coins += 7
if (has_pipe_up(state, player) or auto_scroll) and state.has("Water Physics", player):
reachable_coins += 6
if has_pipe_right(state, player) and not auto_scroll:
reachable_coins += 1
if state.has_any(["Mushroom", "Fire Flower"], player):
reachable_coins += 5
return coins <= reachable_coins
def pumpkin_zone_secret_course_1_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Pumpkin Zone Secret Course 1")
# We'll be a bit forgiving. I was able to reach 43 while small.
if coins <= 40:
return True
if state.has("Carrot", player):
if auto_scroll:
return coins <= 172
return True
return False
def pumpkin_zone_3_secret_exit(state, player):
return state.has("Carrot", player)
def pumpkin_zone_3_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Pumpkin Zone 3")
reachable_coins = 38
if has_pipe_up(state, player) and ((not auto_scroll) or has_pipe_down(state, player)):
reachable_coins += 12
if has_pipe_down(state, player) and not auto_scroll:
reachable_coins += 11
return coins <= reachable_coins
def pumpkin_zone_4_boss(state, player):
return has_pipe_right(state, player)
def pumpkin_zone_4_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Pumpkin Zone 4")
reachable_coins = 29
if has_pipe_down(state, player):
if auto_scroll:
if has_pipe_up(state, player):
reachable_coins += 16
else:
reachable_coins += 4
else:
reachable_coins += 28
# both sets of coins are down, but you need pipe up to return to go down to the next set in one playthrough
if has_pipe_up(state, player):
reachable_coins += 16
return coins <= reachable_coins
def mario_zone_1_normal_exit(state, player):
if has_pipe_right(state, player):
if state.has_any(["Mushroom", "Fire Flower", "Carrot", "Mario Zone 1 Midway Bell"], player):
return True
if is_auto_scroll(state, player, "Mario Zone 1"):
return True
return False
def mario_zone_1_midway_bell(state, player):
# It is possible to get as small mario, but it is a very precise jump and you will die afterward.
return ((state.has_any(["Mushroom", "Fire Flower", "Carrot"], player) and has_pipe_right(state, player))
or state.has("Mario Zone 1 Midway Bell", player))
def mario_zone_1_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Mario Zone 1")
reachable_coins = 0
if has_pipe_right(state, player) or (has_pipe_left(state, player)
and state.has("Mario Zone 1 Midway Bell", player) and not auto_scroll):
reachable_coins += 32
if has_pipe_right(state, player) and (state.has_any(["Mushroom", "Fire Flower", "Carrot"], player)
or not auto_scroll):
reachable_coins += 8
# coins from end section. I was able to get 13 as small mario, giving some leniency
if state.has("Carrot", player):
reachable_coins += 28
else:
reachable_coins += 12
if state.has("Fire Flower", player) and not auto_scroll:
reachable_coins += 46
return coins <= reachable_coins
def mario_zone_3_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Mario Zone 3")
reachable_coins = 10
if state.has("Carrot", player):
reachable_spike_coins = 15
else:
sprites = state.multiworld.worlds[player].sprite_data["Mario Zone 3"]
reachable_spike_coins = min(3, len({sprites[i]["sprite"] == "Claw Grabber" for i in (17, 18, 25)})
+ state.has("Mushroom", player) + state.has("Fire Flower", player)) * 5
reachable_coins += reachable_spike_coins
if not auto_scroll:
reachable_coins += 10
if state.has("Fire Flower", player):
reachable_coins += 22
if auto_scroll:
reachable_coins -= 3 + reachable_spike_coins
return coins <= reachable_coins
def mario_zone_4_boss(state, player):
return has_pipe_right(state, player)
def mario_zone_4_coins(state, player, coins):
return coins <= 60 or not is_auto_scroll(state, player, "Mario Zone 4")
def not_blocked_by_sharks(state, player):
sharks = [state.multiworld.worlds[player].sprite_data["Turtle Zone 1"][i]["sprite"]
for i in (27, 28)].count("Shark")
if state.has("Carrot", player) or not sharks:
return True
if sharks == 2:
return state.has_all(["Mushroom", "Fire Flower"], player)
if sharks == 1:
return state.has_any(["Mushroom", "Fire Flower"], player)
return False
def turtle_zone_1_normal_exit(state, player):
return not_blocked_by_sharks(state, player)
def turtle_zone_1_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Turtle Zone 1")
reachable_coins = 30
if not_blocked_by_sharks(state, player):
reachable_coins += 13
if auto_scroll:
reachable_coins -= 1
if state.has("Water Physics", player) or state.has("Carrot", player):
reachable_coins += 10
if state.has("Carrot", player):
reachable_coins += 24
if auto_scroll:
reachable_coins -= 10
return coins <= reachable_coins
def turtle_zone_2_normal_exit(state, player):
return (has_pipe_up(state, player) and has_pipe_down(state, player) and has_pipe_right(state, player) and
has_pipe_left(state, player) and state.has("Water Physics", player)
and not is_auto_scroll(state, player, "Turtle Zone 2"))
def turtle_zone_2_secret_exit(state, player):
return (has_pipe_up(state, player) and state.has("Water Physics", player)
and not is_auto_scroll(state, player, "Turtle Zone 2"))
def turtle_zone_2_midway_bell(state, player):
return ((state.has("Water Physics", player) and not is_auto_scroll(state, player, "Turtle Zone 2"))
or state.has("Turtle Zone 2 Midway Bell", player))
def turtle_zone_2_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Turtle Zone 2")
reachable_coins = 2
if auto_scroll:
if state.has("Water Physics", player):
reachable_coins += 6
else:
reachable_coins += 2
if state.has("Water Physics", player):
reachable_coins += 20
elif state.has("Turtle Zone 2 Midway Bell", player):
reachable_coins += 4
if (has_pipe_right(state, player) and has_pipe_down(state, player)
and state.has_any(["Water Physics", "Turtle Zone 2 Midway Bell"], player)):
reachable_coins += 1
if has_pipe_left(state, player) and has_pipe_up(state, player):
reachable_coins += 1
if state.has("Water Physics", player):
reachable_coins += 1
return coins <= reachable_coins
def turtle_zone_secret_course_normal_exit(state, player):
return state.has_any(["Fire Flower", "Carrot"], player)
def turtle_zone_secret_course_coins(state, player, coins):
reachable_coins = 53
if state.has("Carrot", player):
reachable_coins += 44
elif state.has("Fire Flower", player):
reachable_coins += 36 # was able to get 38, some leniency
return coins <= reachable_coins
def turtle_zone_3_boss(state, player):
return has_pipe_right(state, player)
def turtle_zone_3_coins(state, player, coins):
return state.has_any(["Water Physics", "Mushroom", "Fire Flower", "Carrot"], player) or coins <= 51
def hippo_zone_normal_or_secret_exit(state, player):
return (state.has_any(["Hippo Bubble", "Water Physics"], player)
or (state.has("Carrot", player)
and not is_auto_scroll(state, player, "Hippo Zone")))
def hippo_zone_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Hippo Zone")
# This is all somewhat forgiving.
reachable_coins = 4
if auto_scroll:
if state.has("Hippo Bubble", player):
reachable_coins = 160
elif state.has("Carrot", player):
reachable_coins = 90
elif state.has("Water Physics", player):
reachable_coins = 28
else:
if state.has_any(["Water Physics", "Hippo Bubble", "Carrot"], player):
reachable_coins += 108
if state.has_any(["Mushroom", "Fire Flower", "Hippo Bubble"], player):
reachable_coins += 6
if state.has_all(["Fire Flower", "Water Physics"], player):
reachable_coins += 1
if state.has("Hippo Bubble", player):
reachable_coins += 52
return coins <= reachable_coins
def space_zone_1_normal_exit(state, player):
# It is possible, however tricky, to beat the Moon Stage without Carrot or Space Physics.
# However, it requires somewhat precisely jumping off enemies. Enemy shuffle may make this impossible.
# Instead, I will just always make one or the other required, since it is difficult without them anyway.
return state.has_any(["Space Physics", "Carrot"], player)
def space_zone_1_secret_exit(state, player):
# One or the other is actually necessary for the secret exit.
return state.has_any(["Space Physics", "Carrot"], player) and not is_auto_scroll(state, player, "Space Zone 1")
def space_zone_1_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Space Zone 1")
if auto_scroll:
reachable_coins = 12
if state.has_any(["Carrot", "Space Physics"], player):
reachable_coins += 20
# If you have Space Physics, you can't make it up to the upper section. We have to assume you might have it,
# so the coins up there must be out of logic if there is auto scrolling.
if state.has("Space Physics", player):
reachable_coins += 40
return coins <= reachable_coins
return (coins <= 21 or (coins <= 50 and state.has_any(["Mushroom", "Fire Flower"], player))
or state.has_any(["Carrot", "Space Physics"], player))
def space_zone_2_midway_bell(state, player):
return state.has_any(["Space Physics", "Space Zone 2 Midway Bell", "Mushroom", "Fire Flower", "Carrot"], player)
def space_zone_2_boss(state, player):
if has_pipe_right(state, player):
if state.has("Space Physics", player):
return True
if (state.has("Space Zone 2 Midway Bell", player)
or not state.multiworld.worlds[player].options.shuffle_midway_bells):
# Reaching the midway bell without space physics requires taking damage once. Reaching the end pipe from the
# midway bell also requires taking damage once.
if state.has_any(["Mushroom", "Fire Flower", "Carrot"], player):
return True
else:
# With no midway bell, you'll have to be able to take damage twice.
if state.has("Mushroom", player) and state.has_any(["Fire Flower", "Carrot"], player):
return True
return False
def space_zone_2_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Space Zone 2")
reachable_coins = 12
if state.has_any(["Mushroom", "Fire Flower", "Carrot", "Space Physics"], player):
reachable_coins += 15
if state.has("Space Physics", player) or not auto_scroll:
reachable_coins += 4 # last few bottom row question mark blocks that are hard to get when auto scrolling.
if (state.has("Space Physics", player) or (
state.has("Mushroom", player) and state.has_any(["Fire Flower", "Carrot"], player))):
reachable_coins += 3
if state.has("Space Physics", player):
reachable_coins += 79
if not auto_scroll:
reachable_coins += 21
return coins <= reachable_coins
def space_zone_secret_course_coins(state, player, coins):
return coins <= 96 or not is_auto_scroll(state, player, "Space Zone Secret Course")
def macro_zone_1_normal_exit(state, player):
return has_pipe_down(state, player) or state.has("Macro Zone 1 Midway Bell", player)
def macro_zone_1_secret_exit(state, player):
return state.has("Fire Flower", player) and has_pipe_up(state, player) and macro_zone_1_midway_bell(state, player)
def macro_zone_1_midway_bell(state, player):
return has_pipe_down(state, player) or state.has("Macro Zone 1 Midway Bell", player)
def macro_zone_1_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Macro Zone 1")
reachable_coins = 0
if has_pipe_down(state, player):
reachable_coins += 69
if auto_scroll:
if state.has_any(["Mushroom", "Fire Flower"], player):
reachable_coins += 5
else:
reachable_coins += 9
if state.has("Fire Flower", player):
reachable_coins += 19
elif state.has("Macro Zone 1 Midway Bell", player):
if auto_scroll:
reachable_coins += 16
if state.has_any(["Mushroom", "Fire Flower"], player):
reachable_coins += 5
else:
reachable_coins += 67
return coins <= reachable_coins
def macro_zone_secret_course_coins(state, player, coins):
return state.has_any(["Mushroom", "Fire Flower"], player)
def macro_zone_2_normal_exit(state, player):
return (has_pipe_down(state, player) or state.has("Macro Zone 2 Midway Bell", player)) and state.has(
"Water Physics", player) and has_pipe_up(state, player) and not is_auto_scroll(state, player, "Macro Zone 2")
def macro_zone_2_midway_bell(state, player):
return ((has_pipe_down(state, player) and state.has("Water Physics", player))
or state.has("Macro Zone 2 Midway Bell", player))
def macro_zone_2_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Macro Zone 2")
if coins <= 27:
return True
if has_pipe_up(state, player) and state.has("Water Physics", player) and not auto_scroll:
if has_pipe_down(state, player):
return True
if state.has("Macro Zone 2 Midway Bell", player):
# Cannot return to the first section from the bell
return coins <= 42
return False
def macro_zone_3_normal_exit(state, player):
return ((has_pipe_down(state, player) and has_pipe_up(state, player))
or state.has("Macro Zone 3 Midway Bell", player))
def macro_zone_3_midway_bell(state, player):
return macro_zone_3_normal_exit(state, player)
def macro_zone_3_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Macro Zone 3")
reachable_coins = 7
if not auto_scroll:
reachable_coins += 17
if has_pipe_up(state, player) and has_pipe_down(state, player):
if auto_scroll:
reachable_coins += 56
else:
return True
elif has_pipe_up(state, player):
if auto_scroll:
reachable_coins += 12
else:
reachable_coins += 36
elif has_pipe_down(state, player):
reachable_coins += 18
if state.has("Macro Zone 3 - Midway Bell", player):
reachable_coins = max(reachable_coins, 30)
return coins <= reachable_coins
def macro_zone_4_boss(state, player):
return has_pipe_right(state, player)
def macro_zone_4_coins(state, player, coins):
auto_scroll = is_auto_scroll(state, player, "Macro Zone 4")
reachable_coins = 61
if auto_scroll:
reachable_coins -= 8
if state.has("Carrot", player):
reachable_coins += 6
return coins <= reachable_coins
def marios_castle_wario(state, player):
return ((has_pipe_right(state, player) and has_pipe_left(state, player))
or state.has("Mario's Castle Midway Bell", player))
def marios_castle_midway_bell(state, player):
return ((has_pipe_right(state, player) and has_pipe_left(state, player))
or state.has("Mario's Castle Midway Bell", player))

View File

@@ -0,0 +1,198 @@
from Options import Toggle, Choice, NamedRange, Range, PerGameCommonOptions, ItemsAccessibility
from dataclasses import dataclass
class ShuffleGoldenCoins(Choice):
"""
Vanilla: Golden Coins are received when defeating bosses.
Shuffle: Shuffle the Golden Coins into the item pool and make bosses location checks.
Mario Coin Fragment Hunt: You start with all Golden Coins except the Mario Coin, which has been fragmented into many pieces.
You will see a Golden Coin being received when defeating bosses regardless of whether you are actually getting a coin.
"""
display_name = "Shuffle Golden Coins"
default = 0
option_vanilla = 0
option_shuffle = 1
option_mario_coin_fragment_hunt = 2
class GoldenCoinsRequired(Range):
"""
Number of Golden Coins required to enter Mario's Castle. Ignored on Mario Coin Fragment Hunt.
"""
display_name = "Golden Coins Required"
range_start = 0
range_end = 6
default = 6
class MarioCoinFragmentPercentage(Range):
"""
Percentage of filler items to be replaced with Mario Coin Fragments. Note that the Coinsanity and Coinsanity
Checks options will greatly impact the number of replaceable filler items.
"""
display_name = "Mario Coin Fragment Percentage"
range_start = 1
range_end = 50
default = 20
class MarioCoinFragmentsRequiredPercentage(Range):
"""
Percentage of the Mario Coins in the item pool that are required to put the Mario Coin together.
"""
display_name = "Mario Coin Fragments Required Percentage"
range_start = 1
range_end = 100
default = 75
class ShuffleMidwayBells(Toggle):
"""
Shuffle Midway Bells into the item pool. You can always start at the beginning of a level after obtaining the
Midway Bell by holding SELECT while entering the level (until you load into the level).
The Midway Bells in levels will trigger location checks whether this option is on or not, but they will only
set the checkpoint if this is off, otherwise you must obtain the Midway Bell item from the item pool.
"""
display_name = "Shuffle Midway Bells"
class MariosCastleMidwayBell(Toggle):
"""
Adds a Midway Bell to the final stage, just before the Wario fight.
"""
display_name = "Mario's Castle Midway Bell"
class Coinsanity(Toggle):
"""
Shuffles the singular coins found freestanding and in question mark blocks into the item pool, and adds location
checks made by obtaining a sufficient number of coins in particular levels within a single playthrough.
"""
display_name = "Coinsanity"
class CoinsanityChecks(Range):
"""
Number of Coinsanity checks.
A higher number means more checks, and smaller coin amounts per coin item in the item pool.
If Accessibility is set to Full, auto-scroll levels may have a lower maximum count, which may lead to this
value being limited.
"""
display_name = "Coinsanity Checks"
range_start = 31
range_end = 2599
default = 150
class DifficultyMode(Choice):
"""
Play in normal or easy mode. You can also start in Normal Mode with an "upgrade" to Easy Mode in the item pool,
or start in Easy Mode with a Normal Mode "trap" in the item pool.
"""
display_name = "Difficulty Mode"
option_normal = 0
option_easy = 1
option_normal_to_easy = 2
option_easy_to_normal = 3
default = 0
class ShufflePipeTraversal(Choice):
"""
Single: Shuffle a Pipe Traversal item into the item pool, which is required to enter any pipes.
Split: Shuffle 4 Pipe Traversal items, one required for entering pipes from each direction.
Note that being unable to enter pipes is very limiting and affects nearly half of all levels.
"""
display_name = "Shuffle Pipe Traversal"
option_off = 0
option_single = 1
option_split = 2
default = 0
class RandomizeEnemies(Toggle):
"""
Randomize enemies throughout levels.
"""
display_name = "Randomize Enemies"
class RandomizePlatforms(Toggle):
"""
Randomize platforms throughout levels.
"""
display_name = "Randomize Platforms"
class AutoScrollChances(NamedRange):
"""
Chance per eligible level to be made into an auto scroll level. Can also set to Vanilla to leave them unchanged.
"""
display_name = "Auto Scroll Chance"
range_start = 0
range_end = 100
special_range_names = {"vanilla": -1, "none": 0, "all": 100}
default = -1
class AutoScrollMode(Choice):
"""
Always: Any auto scroll levels will always auto-scroll.
Global Trap Item: Auto scroll levels will only auto-scroll after obtaining the Auto Scroll trap item.
Level Trap Items: As with Trap Item, but there is a separate trap item for each auto scroll level.
Global Cancel Item: Auto Scroll levels will stop auto-scrolling after obtaining the Auto Scroll Cancel item.
Level Cancel Items: As with Cancel Item, but there is a separate cancel item for each auto scroll level.
Chaos: Each level will randomly always auto scroll, have an Auto Scroll Trap, or have an Auto Scroll Cancel item.
The effects of Trap and Cancel items are permanent! If Accessibility is not set to Full,
Traps may cause locations to become permanently unreachable.
With individual level items, the number of auto scroll levels may be limited by the available space in the item
pool.
"""
display_name = "Auto Scroll Mode"
option_always = 0
option_global_trap_item = 1
option_level_trap_items = 2
option_global_cancel_item = 3
option_level_cancel_items = 4
option_chaos = 5
default = 0
class RandomizeMusic(Toggle):
"""
Randomize the music that plays in levels and overworld areas.
"""
display_name = "Randomize Music"
class EnergyLink(Toggle):
"""
All extra lives beyond 1 are transferred into the server's shared EnergyLink storage. If you drop to 0,
1 will be replenished if there is sufficient energy stored.
"""
display_name = "Energy Link"
default = 1
@dataclass
class SML2Options(PerGameCommonOptions):
accessibility: ItemsAccessibility
shuffle_golden_coins: ShuffleGoldenCoins
required_golden_coins: GoldenCoinsRequired
mario_coin_fragment_percentage: MarioCoinFragmentPercentage
mario_coin_fragments_required_percentage: MarioCoinFragmentsRequiredPercentage
coinsanity: Coinsanity
coinsanity_checks: CoinsanityChecks
shuffle_midway_bells: ShuffleMidwayBells
marios_castle_midway_bell: MariosCastleMidwayBell
shuffle_pipe_traversal: ShufflePipeTraversal
auto_scroll_mode: AutoScrollMode
auto_scroll_chances: AutoScrollChances
difficulty_mode: DifficultyMode
randomize_enemies: RandomizeEnemies
randomize_platforms: RandomizePlatforms
randomize_music: RandomizeMusic
energy_link: EnergyLink

146
worlds/marioland2/rom.py Normal file
View File

@@ -0,0 +1,146 @@
import hashlib
import os
import pkgutil
import Utils
from worlds.Files import APProcedurePatch, APTokenMixin, APTokenTypes
from settings import get_settings
from .rom_addresses import rom_addresses
from .sprites import sprite_name_to_id
def randomize_music(patch, random):
# overworld
overworld_music_tracks = [0x05, 0x06, 0x0D, 0x0E, 0x10, 0x12, 0x1B, 0x1C, 0x1E]
random.shuffle(overworld_music_tracks)
for i, track in zip([0x3004F, 0x3EA9B, 0x3D186, 0x3D52B, 0x3D401, 0x3D297, 0x3D840, 0x3D694, 0x3D758],
overworld_music_tracks):
patch.write_bytes(i, track)
# levels
for i in range(0x5619, 0x5899, 0x14):
patch.write_bytes(i, random.choice([0x01, 0x0B, 0x11, 0x13, 0x14, 0x17, 0x1D, 0x1F, 0x28]))
def generate_output(self, output_directory: str):
patch = SuperMarioLand2ProcedurePatch(player=self.player, player_name=self.player_name)
patch.write_file("basepatch.bsdiff4", pkgutil.get_data(__name__, "basepatch.bsdiff4"))
random = self.random
if self.options.marios_castle_midway_bell:
# Remove Question Mark Block
patch.write_bytes(0x4F012, 0x5D)
# Fix level pointer to read midway bell flag
patch.write_bytes(0x3E569, 0x18)
patch.write_bytes(0x3E56A, 0x18)
# Position and screen coordinates
patch.write_bytes(0x383B, [0xD4, 0x01, 0x4D, 0x0A, 0xC0, 0x01, 0x50, 0x0A])
if self.options.coinsanity:
# Add platform to return to start of Pumpkin Zone Secret Course 1
patch.write_bytes(0x258B6, 0x3B)
patch.write_bytes(0x258F8, 0x7a)
patch.write_bytes(0x2594D, 0x67)
patch.write_bytes(0x259A8, 0x68)
patch.write_bytes(0x259A9, 0x60)
i = 0xe077
for level, sprites in self.sprite_data.items():
for sprite_data in sprites:
sprite_id = sprite_name_to_id[sprite_data["sprite"]]
data = [((sprite_id & 0b01000000) >> 2) | ((sprite_id & 0b00111000) << 2) | sprite_data["screen"],
((sprite_id & 0b00000111) << 5) | sprite_data["x"],
sprite_data["misc"] | sprite_data["y"]]
patch.write_bytes(i, data)
i += 3
patch.write_bytes(i, 255)
i += 1
if self.options.randomize_music:
randomize_music(patch, random)
if self.options.shuffle_golden_coins:
patch.write_bytes(rom_addresses["Coin_Shuffle"], 0x40)
if self.options.shuffle_midway_bells:
patch.write_bytes(rom_addresses["Disable_Midway_Bell"], 0xC9)
if self.options.coinsanity:
for section in ("A", "B"):
for i in range(0, 30):
patch.write_bytes(rom_addresses[f"Coinsanity_{section}"] + i, 0x00)
star_count = max(len([loc for loc in self.multiworld.get_filled_locations() if loc.item.player == self.player
and loc.item.name == "Super Star Duration Increase"]), 1)
patch.write_bytes(rom_addresses["Star_Count"], star_count // 256)
patch.write_bytes(rom_addresses["Star_Count"] + 1, star_count - (star_count // 256))
if self.options.shuffle_golden_coins == "mario_coin_fragment_hunt":
patch.write_bytes(rom_addresses["Coins_Required"], self.coin_fragments_required // 256)
patch.write_bytes(rom_addresses["Coins_Required"] + 1, self.coin_fragments_required % 256)
patch.write_bytes(rom_addresses["Required_Golden_Coins"], 6)
else:
patch.write_bytes(rom_addresses["Coins_Required"] + 1, self.options.required_golden_coins.value)
patch.write_bytes(rom_addresses["Required_Golden_Coins"], self.options.required_golden_coins.value)
patch.write_bytes(rom_addresses["Midway_Bells"], self.options.shuffle_midway_bells.value)
patch.write_bytes(rom_addresses["Energy_Link"], self.options.energy_link.value)
patch.write_bytes(rom_addresses["Difficulty_Mode"], self.options.difficulty_mode.value)
patch.write_bytes(rom_addresses["Coin_Mode"], self.options.shuffle_golden_coins.value)
for level, i in enumerate(self.auto_scroll_levels):
# We set 0 if no auto scroll or auto scroll trap, so it defaults to no auto scroll. 1 if always or cancel items.
patch.write_bytes(rom_addresses["Auto_Scroll_Levels"] + level, max(0, i - 1))
patch.write_bytes(rom_addresses["Auto_Scroll_Levels_B"] + level, i)
if self.options.energy_link:
# start with 1 life if Energy Link is on so that you don't deposit lives at the start of the game.
patch.write_bytes(rom_addresses["Starting_Lives"], 1)
rom_name = bytearray(f'AP{Utils.__version__.replace(".", "")[0:3]}_{self.player}_{self.multiworld.seed:11}\0',
'utf8')[:21]
rom_name.extend([0] * (21 - len(rom_name)))
patch.write_bytes(0x77777, rom_name)
patch.write_file("tokens.bin", patch.get_token_binary())
patch.write(os.path.join(output_directory,
f"{self.multiworld.get_out_file_name_base(self.player)}{patch.patch_file_ending}"))
class SuperMarioLand2ProcedurePatch(APProcedurePatch, APTokenMixin):
hash = "a8413347d5df8c9d14f97f0330d67bce"
patch_file_ending = ".apsml2"
game = "Super Mario Land 2"
result_file_ending = ".gb"
procedure = [
("apply_bsdiff4", ["basepatch.bsdiff4"]),
("apply_tokens", ["tokens.bin"]),
]
@classmethod
def get_source_data(cls) -> bytes:
return get_base_rom_bytes()
def write_bytes(self, offset, value):
if isinstance(value, int):
value = [value]
self.write_token(APTokenTypes.WRITE, offset, bytes(value))
def get_base_rom_bytes():
file_name = get_base_rom_path()
with open(file_name, "rb") as file:
base_rom_bytes = bytes(file.read())
basemd5 = hashlib.md5()
basemd5.update(base_rom_bytes)
if SuperMarioLand2ProcedurePatch.hash != basemd5.hexdigest():
raise Exception("Supplied Base Rom does not match known MD5 for Super Mario Land 1.0. "
"Get the correct game and version, then dump it")
return base_rom_bytes
def get_base_rom_path():
file_name = get_settings()["sml2_options"]["rom_file"]
if not os.path.exists(file_name):
file_name = Utils.user_path(file_name)
return file_name

View File

@@ -0,0 +1,39 @@
rom_addresses = {
"Space_Physics": 0x4e7,
"Pipe_Traversal_A": 0x11a4,
"Pipe_Traversal_SFX_A": 0x11a9,
"Pipe_Traversal_B": 0x11d6,
"Pipe_Traversal_SFX_B": 0x11e7,
"Pipe_Traversal_C": 0x1226,
"Pipe_Traversal_SFX_C": 0x123f,
"Pipe_Traversal_D": 0x1256,
"Pipe_Traversal_SFX_D": 0x125b,
"Enable_Swim": 0x1d17,
"Coinsanity_B": 0x1d86,
"Auto_Scroll_Levels": 0x1f71,
"Starting_Lives": 0x2920,
"Get_Hurt_To_Big_Mario": 0x31c7,
"Get_Mushroom_A": 0x345c,
"Get_Fire_Flower_A": 0x346d,
"Get_Carrot_A": 0x347e,
"Invincibility_Star_A": 0x349e,
"Invincibility_Star_B": 0x34a3,
"Enable_Bubble": 0x34e5,
"Coinsanity_A": 0x591f,
"Coin_Shuffle": 0x304ce,
"Required_Golden_Coins": 0x306e9,
"Disable_Midway_Bell": 0x3ef1e,
"Get_Carrot_C": 0x6092f,
"Get_Mushroom_C": 0x60930,
"Get_Fire_Flower_C": 0x60933,
"Get_Mushroom_B": 0x60ddb,
"Get_Carrot_B": 0x60de7,
"Get_Fire_Flower_B": 0x60df3,
"Coins_Required": 0x80139,
"Difficulty_Mode": 0x8013b,
"Star_Count": 0x8013c,
"Midway_Bells": 0x8013e,
"Energy_Link": 0x8013f,
"Coin_Mode": 0x80140,
"Auto_Scroll_Levels_B": 0x80141,
}

View File

@@ -0,0 +1,131 @@
# Based on SML2R enemy and platform randomizer
# # https://github.com/slashinfty/sml2r-node/blob/862128c73d336d6cbfbf6290c09f3eff103688e8/src/index.ts#L284
def randomize_enemies(sprite_data, random):
for level, level_sprite_data in sprite_data.items():
shuffle = ()
if level in ("Mushroom Zone", "Macro Zone 4"):
shuffle = ("Koopa Troopa", "Goomba", "Paragoomba (Vertical)", "Paragoomba (Diagonal)")
elif level in ("Scenic Course", "Pumpkin Zone Secret Course 1"):
shuffle = ("Goomba", "Paragoomba (Vertical)", "Paragoomba (Diagonal)")
elif level == "Tree Zone 1":
shuffle = ("Money Bag/Bopping Toady", "Ragumo/Aqua Kuribo", "Pencil/Spikey", "Kyotonbo")
elif level == "Tree Zone 2":
shuffle = ("Noko Bombette/Bear", "No 48/Mogyo")
elif level == "Tree Zone 3":
shuffle = ("Battle Beetle", "Be", "Ant")
elif level == "Tree Zone 5":
shuffle = ("Paragoomba (Diagonal)", "Dondon", "Paragoomba (Vertical)")
elif level == "Pumpkin Zone 2":
shuffle = ("Boo/Bomubomu", "Kyororo", "Honebon/F Boy", "Karakara", "Star (Vertical)/Blurp (Horizontal)",
"Star (Horizontal)/Blurp (Vertical)")
elif level == "Pumpkin Zone 3":
shuffle = ("Boo/Bomubomu", "Unibo/Terekuribo")
elif level == "Mario Zone 1":
shuffle = ("Koopa Troopa", "Neiji/Buichi", "Tatenoko")
elif level == "Mario Zone 2":
shuffle = ("Paragoomba (Diagonal)", "Goomba", "Paragoomba (Vertical)", "Noko Bombette/Bear",
"Boo/Bomubomu")
elif level == "Turtle Zone 1":
shuffle = ("Horizontal Blurp", "Shark", "Cheep Cheep (Vertical)", "Paragoomba (Diagonal)", "Goomba",
"Spiny Cheep Cheep", "Paragoomba (Vertical)",
"Owl Platform (Horizontal)/Cheep Cheep (Horizontal)")
elif level == "Hippo Zone":
shuffle = ("Horizontal Blurp", "Dondon", "Unibo/Terekuribo", "Toriuo")
elif level == "Space Zone 2":
shuffle = ("Tosenbo/Pikku", "Star (Vertical)/Blurp (Horizontal)", "Star (Horizontal)/Blurp (Vertical)")
elif level == "Macro Zone 1":
shuffle = ("Kyotonbo", "Goronto", "Dokanto", "Chikunto")
elif level == "Macro Zone 2":
shuffle = ("Cheep Cheep (Vertical)", "Battle Beetle", "Be",
"Owl Platform (Horizontal)/Cheep Cheep (Horizontal)", "Ant")
elif level == "Macro Zone 3":
shuffle = ("Koopa Troopa", "Paragoomba (Diagonal)", "Goomba", "Be", "Paragoomba (Vertical)",
"Honebon/F Boy")
elif level == "Pumpkin Zone Secret Course 2":
shuffle = ("Koopa Troopa", "Goomba")
for sprite in level_sprite_data:
if level == "Pumpkin Zone 1":
if sprite["sprite"] == "Falling Spike":
shuffle = ("Boo/Bomubomu", "Falling Spike", "Kurokyura/Jack-in-the-Box", "Masked Ghoul/Bullet Bill")
elif sprite["sprite"] == "Falling Spike on Chain":
shuffle = ("Boo/Bomubomu", "Falling Spike on Chain", "Kurokyura/Jack-in-the-Box",
"Masked Ghoul/Bullet Bill")
else:
shuffle = ("Boo/Bomubomu", "Kurokyura/Jack-in-the-Box", "Masked Ghoul/Bullet Bill")
elif level == "Pumpkin Zone 4":
if sprite["sprite"] == "Falling Spike on Chain":
shuffle = ("Boo/Bomubomu", "Falling Spike on Chain", "Masked Ghoul/Bullet Bill", "Rerere/Poro",
"Tosenbo/Pikku")
else:
shuffle = ("Boo/Bomubomu", "Masked Ghoul/Bullet Bill", "Rerere/Poro", "Tosenbo/Pikku")
elif level == "Mario Zone 3":
if sprite["sprite"] == "Claw Grabber":
shuffle = ("Koopa Troopa", "Diagonal Ball on Chain", "Kiddokatto", "Claw Grabber",
"Masked Ghoul/Bullet Bill")
elif sprite["sprite"] in ("Koopa Troopa", "Diagonal Ball on Chain", "Kiddokatto"):
shuffle = ("Koopa Troopa", "Diagonal Ball on Chain", "Kiddokatto", "Masked Ghoul/Bullet Bill")
else:
shuffle = ()
elif level == "Mario Zone 4":
if sprite["sprite"] == "Spinning Spike/Tamara":
shuffle = ("Goomba", "Spinning Spike/Tamara", "Boo/Bomubomu", "Masked Ghoul/Bullet Bill")
elif sprite["sprite"] == "Moving Saw (Floor)":
shuffle = ("Goomba", "Moving Saw (Floor)", "Boo/Bomubomu", "Masked Ghoul/Bullet Bill")
else:
shuffle = ("Goomba", "Boo/Bomubomu", "Masked Ghoul/Bullet Bill")
elif level == "Turtle Zone 3":
if sprite["sprite"] == "Pencil/Spikey":
shuffle = ("Koopa Troopa", "Paragoomba (Diagonal)", "Ragumo/Aqua Kuribo", "Pencil/Spikey",
"Paragoomba (Vertical)", "Honebon/F Boy")
else:
shuffle = ("Koopa Troopa", "Paragoomba (Diagonal)", "Ragumo/Aqua Kuribo",
"Paragoomba (Vertical)", "Honebon/F Boy")
elif level == "Space Zone 1":
if sprite["sprite"] == "Boo/Bomubomu":
shuffle = ("Boo/Bomubomu", "No 48/Mogyo")
else:
shuffle = ("Boo/Bomubomu", "No 48/Mogyo", "Rerere/Poro")
elif level == "Mario's Castle":
if sprite["sprite"] in ("Fire Pakkun Zo (Large)", "Fire Pakkun Zo (Left)"):
shuffle = ("Fire Pakkun Zo (Large)", "Fire Pakkun Zo (Left)")
else:
shuffle = ("Spike Ball (Large)", "Spike Ball (Small)")
elif level == "Tree Zone 4":
# Deviation from SML2R: No Buichis placed into non-Buichi locations, as they can place under the
# underground question mark blocks. Potentially could make a list of which ones are allowed to become
# Buichis?
if sprite["sprite"] in ("Runaway Heart Block/Bibi", "Piranha Plant (Downward)/Grubby",
"Spinning Platform (Horizontal)/Skeleton Bee",
"Spinning Spike (Horizontal)/Unera"):
shuffle = ("Runaway Heart Block/Bibi", "Piranha Plant (Downward)/Grubby",
"Spinning Platform (Horizontal)/Skeleton Bee", "Spinning Spike (Horizontal)/Unera")
elif sprite["sprite"] == "Neiji/Buichi":
shuffle = ("Runaway Heart Block/Bibi", "Neiji/Buichi", "Piranha Plant (Downward)/Grubby",
"Spinning Platform (Horizontal)/Skeleton Bee", "Spinning Spike (Horizontal)/Unera")
else:
shuffle = ()
if sprite["sprite"] in ("Piranha Plant", "Fire Piranha Plant"):
if level not in ("Pumpkin Zone 2", "Pumpkin Zone 4", "Macro Zone 3"):
shuffle = ("Piranha Plant", "Fire Piranha Plant")
if sprite["sprite"] in shuffle:
sprite["sprite"] = random.choice(shuffle)
elif level == "Mario's Castle" and sprite["sprite"] == "Karamenbo" and not random.randint(0, 9):
sprite["y"] += 1
def randomize_platforms(sprite_data, random):
shuffle = ("Moving Platform (Small, Vertical)", "Moving Platform (Large, Vertical)",
"Moving Platform (Small, Horizontal)", "Moving Platform (Large, Horizontal)",
"Moving Platform (Large, Diagonal)", "Falling Platform")
for sprite in sprite_data["Tree Zone 3"]:
if sprite["sprite"] in shuffle:
sprite["sprite"] = random.choice(shuffle)
shuffle = ("Cloud Platform (Horizontal)", "Owl Platform (Horizontal)/Cheep Cheep (Horizontal)")
for sprite in sprite_data["Tree Zone 5"]:
if sprite["sprite"] in shuffle:
sprite["sprite"] = random.choice(shuffle)
shuffle = ("Falling Bone Platform", "Rising Bone Platform", "Skull Platform")
for sprite in sprite_data["Mario's Castle"]:
if sprite["sprite"] in shuffle:
sprite["sprite"] = random.choice(shuffle)

1016
worlds/marioland2/sprites.py Normal file

File diff suppressed because it is too large Load Diff