forked from mirror/Archipelago
Merge branch 'main' of https://github.com/Magnemania/Archipelago into sc2wol
This commit is contained in:
@@ -40,6 +40,7 @@ class MultiWorld():
|
||||
plando_connections: List
|
||||
worlds: Dict[int, auto_world]
|
||||
groups: Dict[int, Group]
|
||||
regions: List[Region]
|
||||
itempool: List[Item]
|
||||
is_race: bool = False
|
||||
precollected_items: Dict[int, List[Item]]
|
||||
@@ -50,6 +51,9 @@ class MultiWorld():
|
||||
non_local_items: Dict[int, Options.NonLocalItems]
|
||||
progression_balancing: Dict[int, Options.ProgressionBalancing]
|
||||
completion_condition: Dict[int, Callable[[CollectionState], bool]]
|
||||
indirect_connections: Dict[Region, Set[Entrance]]
|
||||
exclude_locations: Dict[int, Options.ExcludeLocations]
|
||||
|
||||
|
||||
class AttributeProxy():
|
||||
def __init__(self, rule):
|
||||
@@ -87,6 +91,7 @@ class MultiWorld():
|
||||
self.customitemarray = []
|
||||
self.shuffle_ganon = True
|
||||
self.spoiler = Spoiler(self)
|
||||
self.indirect_connections = {}
|
||||
self.fix_trock_doors = self.AttributeProxy(
|
||||
lambda player: self.shuffle[player] != 'vanilla' or self.mode[player] == 'inverted')
|
||||
self.fix_skullwoods_exit = self.AttributeProxy(
|
||||
@@ -295,6 +300,13 @@ class MultiWorld():
|
||||
def get_file_safe_player_name(self, player: int) -> str:
|
||||
return ''.join(c for c in self.get_player_name(player) if c not in '<>:"/\\|?*')
|
||||
|
||||
def get_out_file_name_base(self, player: int) -> str:
|
||||
""" the base name (without file extension) for each player's output file for a seed """
|
||||
return f"AP_{self.seed_name}_P{player}" \
|
||||
+ (f"_{self.get_file_safe_player_name(player).replace(' ', '_')}"
|
||||
if (self.player_name[player] != f"Player{player}")
|
||||
else '')
|
||||
|
||||
def initialize_regions(self, regions=None):
|
||||
for region in regions if regions else self.regions:
|
||||
region.world = self
|
||||
@@ -404,6 +416,11 @@ class MultiWorld():
|
||||
def clear_entrance_cache(self):
|
||||
self._cached_entrances = None
|
||||
|
||||
def register_indirect_condition(self, region: Region, entrance: Entrance):
|
||||
"""Report that access to this Region can result in unlocking this Entrance,
|
||||
state.can_reach(Region) in the Entrance's traversal condition, as opposed to pure transition logic."""
|
||||
self.indirect_connections.setdefault(region, set()).add(entrance)
|
||||
|
||||
def get_locations(self) -> List[Location]:
|
||||
if self._cached_locations is None:
|
||||
self._cached_locations = [location for region in self.regions for location in region.locations]
|
||||
@@ -529,7 +546,7 @@ class MultiWorld():
|
||||
|
||||
beatable_fulfilled = False
|
||||
|
||||
def location_conditition(location: Location):
|
||||
def location_condition(location: Location):
|
||||
"""Determine if this location has to be accessible, location is already filtered by location_relevant"""
|
||||
if location.player in players["minimal"]:
|
||||
return False
|
||||
@@ -546,7 +563,7 @@ class MultiWorld():
|
||||
def all_done():
|
||||
"""Check if all access rules are fulfilled"""
|
||||
if beatable_fulfilled:
|
||||
if any(location_conditition(location) for location in locations):
|
||||
if any(location_condition(location) for location in locations):
|
||||
return False # still locations required to be collected
|
||||
return True
|
||||
|
||||
@@ -608,7 +625,6 @@ class CollectionState():
|
||||
self.collect(item, True)
|
||||
|
||||
def update_reachable_regions(self, player: int):
|
||||
from worlds.alttp.EntranceShuffle import indirect_connections
|
||||
self.stale[player] = False
|
||||
rrp = self.reachable_regions[player]
|
||||
bc = self.blocked_connections[player]
|
||||
@@ -616,7 +632,7 @@ class CollectionState():
|
||||
start = self.world.get_region('Menu', player)
|
||||
|
||||
# init on first call - this can't be done on construction since the regions don't exist yet
|
||||
if not start in rrp:
|
||||
if start not in rrp:
|
||||
rrp.add(start)
|
||||
bc.update(start.exits)
|
||||
queue.extend(start.exits)
|
||||
@@ -636,8 +652,7 @@ class CollectionState():
|
||||
self.path[new_region] = (new_region.name, self.path.get(connection, None))
|
||||
|
||||
# Retry connections if the new region can unblock them
|
||||
if new_region.name in indirect_connections:
|
||||
new_entrance = self.world.get_entrance(indirect_connections[new_region.name], player)
|
||||
for new_entrance in self.world.indirect_connections.get(new_region, set()):
|
||||
if new_entrance in bc and new_entrance not in queue:
|
||||
queue.append(new_entrance)
|
||||
|
||||
@@ -993,7 +1008,7 @@ class Entrance:
|
||||
|
||||
return False
|
||||
|
||||
def connect(self, region: Region, addresses=None, target=None):
|
||||
def connect(self, region: Region, addresses: Any = None, target: Any = None) -> None:
|
||||
self.connected_region = region
|
||||
self.target = target
|
||||
self.addresses = addresses
|
||||
@@ -1081,7 +1096,7 @@ class Location:
|
||||
show_in_spoiler: bool = True
|
||||
progress_type: LocationProgressType = LocationProgressType.DEFAULT
|
||||
always_allow = staticmethod(lambda item, state: False)
|
||||
access_rule = staticmethod(lambda state: True)
|
||||
access_rule: Callable[[CollectionState], bool] = staticmethod(lambda state: True)
|
||||
item_rule = staticmethod(lambda item: True)
|
||||
item: Optional[Item] = None
|
||||
|
||||
|
||||
@@ -132,12 +132,12 @@ class CommonContext:
|
||||
# defaults
|
||||
starting_reconnect_delay: int = 5
|
||||
current_reconnect_delay: int = starting_reconnect_delay
|
||||
command_processor: type(CommandProcessor) = ClientCommandProcessor
|
||||
command_processor: typing.Type[CommandProcessor] = ClientCommandProcessor
|
||||
ui = None
|
||||
ui_task: typing.Optional[asyncio.Task] = None
|
||||
input_task: typing.Optional[asyncio.Task] = None
|
||||
keep_alive_task: typing.Optional[asyncio.Task] = None
|
||||
server_task: typing.Optional[asyncio.Task] = None
|
||||
ui_task: typing.Optional["asyncio.Task[None]"] = None
|
||||
input_task: typing.Optional["asyncio.Task[None]"] = None
|
||||
keep_alive_task: typing.Optional["asyncio.Task[None]"] = None
|
||||
server_task: typing.Optional["asyncio.Task[None]"] = None
|
||||
server: typing.Optional[Endpoint] = None
|
||||
server_version: Version = Version(0, 0, 0)
|
||||
current_energy_link_value: int = 0 # to display in UI, gets set by server
|
||||
@@ -146,7 +146,7 @@ class CommonContext:
|
||||
|
||||
# remaining type info
|
||||
slot_info: typing.Dict[int, NetworkSlot]
|
||||
server_address: str
|
||||
server_address: typing.Optional[str]
|
||||
password: typing.Optional[str]
|
||||
hint_cost: typing.Optional[int]
|
||||
player_names: typing.Dict[int, str]
|
||||
@@ -154,6 +154,7 @@ class CommonContext:
|
||||
# locations
|
||||
locations_checked: typing.Set[int] # local state
|
||||
locations_scouted: typing.Set[int]
|
||||
items_received: typing.List[NetworkItem]
|
||||
missing_locations: typing.Set[int] # server state
|
||||
checked_locations: typing.Set[int] # server state
|
||||
server_locations: typing.Set[int] # all locations the server knows of, missing_location | checked_locations
|
||||
@@ -163,7 +164,7 @@ class CommonContext:
|
||||
# current message box through kvui
|
||||
_messagebox = None
|
||||
|
||||
def __init__(self, server_address, password):
|
||||
def __init__(self, server_address: typing.Optional[str], password: typing.Optional[str]) -> None:
|
||||
# server state
|
||||
self.server_address = server_address
|
||||
self.username = None
|
||||
@@ -243,7 +244,8 @@ class CommonContext:
|
||||
if self.server_task is not None:
|
||||
await self.server_task
|
||||
|
||||
async def send_msgs(self, msgs):
|
||||
async def send_msgs(self, msgs: typing.List[typing.Any]) -> None:
|
||||
""" `msgs` JSON serializable """
|
||||
if not self.server or not self.server.socket.open or self.server.socket.closed:
|
||||
return
|
||||
await self.server.socket.send(encode(msgs))
|
||||
@@ -271,7 +273,7 @@ class CommonContext:
|
||||
logger.info('Enter slot name:')
|
||||
self.auth = await self.console_input()
|
||||
|
||||
async def send_connect(self, **kwargs):
|
||||
async def send_connect(self, **kwargs: typing.Any) -> None:
|
||||
payload = {
|
||||
'cmd': 'Connect',
|
||||
'password': self.password, 'name': self.auth, 'version': Utils.version_tuple,
|
||||
@@ -282,7 +284,7 @@ class CommonContext:
|
||||
payload.update(kwargs)
|
||||
await self.send_msgs([payload])
|
||||
|
||||
async def console_input(self):
|
||||
async def console_input(self) -> str:
|
||||
self.input_requests += 1
|
||||
return await self.input_queue.get()
|
||||
|
||||
@@ -390,7 +392,7 @@ class CommonContext:
|
||||
|
||||
# DeathLink hooks
|
||||
|
||||
def on_deathlink(self, data: dict):
|
||||
def on_deathlink(self, data: typing.Dict[str, typing.Any]) -> None:
|
||||
"""Gets dispatched when a new DeathLink is triggered by another linked player."""
|
||||
self.last_death_link = max(data["time"], self.last_death_link)
|
||||
text = data.get("cause", "")
|
||||
@@ -477,7 +479,7 @@ async def keep_alive(ctx: CommonContext, seconds_between_checks=100):
|
||||
seconds_elapsed = 0
|
||||
|
||||
|
||||
async def server_loop(ctx: CommonContext, address=None):
|
||||
async def server_loop(ctx: CommonContext, address: typing.Optional[str] = None) -> None:
|
||||
if ctx.server and ctx.server.socket:
|
||||
logger.error('Already connected')
|
||||
return
|
||||
@@ -722,7 +724,7 @@ async def console_loop(ctx: CommonContext):
|
||||
logger.exception(e)
|
||||
|
||||
|
||||
def get_base_parser(description=None):
|
||||
def get_base_parser(description: typing.Optional[str] = None):
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument('--connect', default=None, help='Address of the multiworld host.')
|
||||
|
||||
44
Fill.py
44
Fill.py
@@ -4,9 +4,10 @@ import collections
|
||||
import itertools
|
||||
from collections import Counter, deque
|
||||
|
||||
from BaseClasses import CollectionState, Location, LocationProgressType, MultiWorld, Item
|
||||
from BaseClasses import CollectionState, Location, LocationProgressType, MultiWorld, Item, ItemClassification
|
||||
|
||||
from worlds.AutoWorld import call_all
|
||||
from worlds.generic.Rules import add_item_rule
|
||||
|
||||
|
||||
class FillError(RuntimeError):
|
||||
@@ -209,6 +210,34 @@ def fast_fill(world: MultiWorld,
|
||||
return item_pool[placing:], fill_locations[placing:]
|
||||
|
||||
|
||||
def accessibility_corrections(world: MultiWorld, state: CollectionState, locations, pool=[]):
|
||||
maximum_exploration_state = sweep_from_pool(state, pool)
|
||||
minimal_players = {player for player in world.player_ids if world.accessibility[player] == "minimal"}
|
||||
unreachable_locations = [location for location in world.get_locations() if location.player in minimal_players and
|
||||
not location.can_reach(maximum_exploration_state)]
|
||||
for location in unreachable_locations:
|
||||
if (location.item is not None and location.item.advancement and location.address is not None and not
|
||||
location.locked and location.item.player not in minimal_players):
|
||||
pool.append(location.item)
|
||||
state.remove(location.item)
|
||||
location.item = None
|
||||
location.event = False
|
||||
if location in state.events:
|
||||
state.events.remove(location)
|
||||
locations.append(location)
|
||||
|
||||
if pool:
|
||||
fill_restrictive(world, state, locations, pool)
|
||||
|
||||
|
||||
def inaccessible_location_rules(world: MultiWorld, state: CollectionState, locations):
|
||||
maximum_exploration_state = sweep_from_pool(state, [])
|
||||
unreachable_locations = [location for location in locations if not location.can_reach(maximum_exploration_state)]
|
||||
for location in unreachable_locations:
|
||||
add_item_rule(location, lambda item: not ((item.classification & 0b0011) and
|
||||
world.accessibility[item.player] != 'minimal'))
|
||||
|
||||
|
||||
def distribute_items_restrictive(world: MultiWorld) -> None:
|
||||
fill_locations = sorted(world.get_unfilled_locations())
|
||||
world.random.shuffle(fill_locations)
|
||||
@@ -239,7 +268,15 @@ def distribute_items_restrictive(world: MultiWorld) -> None:
|
||||
defaultlocations = locations[LocationProgressType.DEFAULT]
|
||||
excludedlocations = locations[LocationProgressType.EXCLUDED]
|
||||
|
||||
fill_restrictive(world, world.state, prioritylocations, progitempool, lock=True)
|
||||
prioritylocations_lock = prioritylocations.copy()
|
||||
|
||||
fill_restrictive(world, world.state, prioritylocations, progitempool)
|
||||
accessibility_corrections(world, world.state, prioritylocations, progitempool)
|
||||
|
||||
for location in prioritylocations_lock:
|
||||
if location.item:
|
||||
location.locked = True
|
||||
|
||||
if prioritylocations:
|
||||
defaultlocations = prioritylocations + defaultlocations
|
||||
|
||||
@@ -248,6 +285,9 @@ def distribute_items_restrictive(world: MultiWorld) -> None:
|
||||
if progitempool:
|
||||
raise FillError(
|
||||
f'Not enough locations for progress items. There are {len(progitempool)} more items than locations')
|
||||
accessibility_corrections(world, world.state, defaultlocations)
|
||||
|
||||
inaccessible_location_rules(world, world.state, defaultlocations)
|
||||
|
||||
remaining_fill(world, excludedlocations, filleritempool)
|
||||
if excludedlocations:
|
||||
|
||||
@@ -377,7 +377,7 @@ def roll_meta_option(option_key, game: str, category_dict: Dict) -> Any:
|
||||
if option_key in options:
|
||||
if options[option_key].supports_weighting:
|
||||
return get_choice(option_key, category_dict)
|
||||
return options[option_key]
|
||||
return category_dict[option_key]
|
||||
if game == "A Link to the Past": # TODO wow i hate this
|
||||
if option_key in {"glitches_required", "dark_room_logic", "entrance_shuffle", "goals", "triforce_pieces_mode",
|
||||
"triforce_pieces_percentage", "triforce_pieces_available", "triforce_pieces_extra",
|
||||
|
||||
@@ -132,7 +132,7 @@ components: Iterable[Component] = (
|
||||
Component('Text Client', 'CommonClient', 'ArchipelagoTextClient'),
|
||||
# SNI
|
||||
Component('SNI Client', 'SNIClient',
|
||||
file_identifier=SuffixIdentifier('.apz3', '.apm3', '.apsoe', '.aplttp', '.apsm', '.apsmz3', '.apdkc3')),
|
||||
file_identifier=SuffixIdentifier('.apz3', '.apm3', '.apsoe', '.aplttp', '.apsm', '.apsmz3', '.apdkc3', '.apsmw')),
|
||||
Component('LttP Adjuster', 'LttPAdjuster'),
|
||||
# Factorio
|
||||
Component('Factorio Client', 'FactorioClient'),
|
||||
|
||||
@@ -139,7 +139,7 @@ def adjust(args):
|
||||
vanillaRom = args.baserom
|
||||
if not os.path.exists(vanillaRom) and not os.path.isabs(vanillaRom):
|
||||
vanillaRom = local_path(vanillaRom)
|
||||
if os.path.splitext(args.rom)[-1].lower() in {'.apbp', '.aplttp'}:
|
||||
if os.path.splitext(args.rom)[-1].lower() == '.aplttp':
|
||||
import Patch
|
||||
meta, args.rom = Patch.create_rom_file(args.rom)
|
||||
|
||||
@@ -195,7 +195,7 @@ def adjustGUI():
|
||||
romEntry2 = Entry(romDialogFrame, textvariable=romVar2)
|
||||
|
||||
def RomSelect2():
|
||||
rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc", ".apbp")), ("All Files", "*")])
|
||||
rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc", ".aplttp")), ("All Files", "*")])
|
||||
romVar2.set(rom)
|
||||
|
||||
romSelectButton2 = Button(romDialogFrame, text='Select Rom', command=RomSelect2)
|
||||
@@ -725,7 +725,7 @@ def get_rom_options_frame(parent=None):
|
||||
vars.auto_apply = StringVar(value=adjuster_settings.auto_apply)
|
||||
autoApplyFrame = Frame(romOptionsFrame)
|
||||
autoApplyFrame.grid(row=9, column=0, columnspan=2, sticky=W)
|
||||
filler = Label(autoApplyFrame, text="Automatically apply last used settings on opening .apbp files")
|
||||
filler = Label(autoApplyFrame, text="Automatically apply last used settings on opening .aplttp files")
|
||||
filler.pack(side=TOP, expand=True, fill=X)
|
||||
askRadio = Radiobutton(autoApplyFrame, text='Ask', variable=vars.auto_apply, value='ask')
|
||||
askRadio.pack(side=LEFT, padx=5, pady=5)
|
||||
|
||||
@@ -13,10 +13,12 @@ update_ran = getattr(sys, "frozen", False) # don't run update if environment is
|
||||
|
||||
if not update_ran:
|
||||
for entry in os.scandir(os.path.join(local_dir, "worlds")):
|
||||
if entry.is_dir():
|
||||
req_file = os.path.join(entry.path, "requirements.txt")
|
||||
if os.path.exists(req_file):
|
||||
requirements_files.add(req_file)
|
||||
# skip .* (hidden / disabled) folders
|
||||
if not entry.name.startswith("."):
|
||||
if entry.is_dir():
|
||||
req_file = os.path.join(entry.path, "requirements.txt")
|
||||
if os.path.exists(req_file):
|
||||
requirements_files.add(req_file)
|
||||
|
||||
|
||||
def update_command():
|
||||
|
||||
@@ -100,7 +100,7 @@ _encode = JSONEncoder(
|
||||
).encode
|
||||
|
||||
|
||||
def encode(obj):
|
||||
def encode(obj: typing.Any) -> str:
|
||||
return _encode(_scan_for_TypedTuples(obj))
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ import multiprocessing
|
||||
import subprocess
|
||||
from asyncio import StreamReader, StreamWriter
|
||||
|
||||
from CommonClient import CommonContext, server_loop, gui_enabled, console_loop, \
|
||||
# CommonClient import first to trigger ModuleUpdater
|
||||
from CommonClient import CommonContext, server_loop, gui_enabled, \
|
||||
ClientCommandProcessor, logger, get_base_parser
|
||||
import Utils
|
||||
from worlds import network_data_package
|
||||
|
||||
@@ -165,6 +165,7 @@ class FreeText(Option):
|
||||
|
||||
|
||||
class NumericOption(Option[int], numbers.Integral):
|
||||
default = 0
|
||||
# note: some of the `typing.Any`` here is a result of unresolved issue in python standards
|
||||
# `int` is not a `numbers.Integral` according to the official typestubs
|
||||
# (even though isinstance(5, numbers.Integral) == True)
|
||||
@@ -628,7 +629,7 @@ class VerifyKeys:
|
||||
|
||||
|
||||
class OptionDict(Option[typing.Dict[str, typing.Any]], VerifyKeys):
|
||||
default = {}
|
||||
default: typing.Dict[str, typing.Any] = {}
|
||||
supports_weighting = False
|
||||
|
||||
def __init__(self, value: typing.Dict[str, typing.Any]):
|
||||
@@ -659,7 +660,7 @@ class ItemDict(OptionDict):
|
||||
|
||||
|
||||
class OptionList(Option[typing.List[typing.Any]], VerifyKeys):
|
||||
default = []
|
||||
default: typing.List[typing.Any] = []
|
||||
supports_weighting = False
|
||||
|
||||
def __init__(self, value: typing.List[typing.Any]):
|
||||
|
||||
424
Patch.py
424
Patch.py
@@ -1,266 +1,33 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import json
|
||||
import bsdiff4
|
||||
import yaml
|
||||
import os
|
||||
import lzma
|
||||
import threading
|
||||
import concurrent.futures
|
||||
import zipfile
|
||||
import sys
|
||||
from typing import Tuple, Optional, Dict, Any, Union, BinaryIO
|
||||
from typing import Tuple, Optional, TypedDict
|
||||
|
||||
import ModuleUpdate
|
||||
ModuleUpdate.update()
|
||||
if __name__ == "__main__":
|
||||
import ModuleUpdate
|
||||
ModuleUpdate.update()
|
||||
|
||||
import Utils
|
||||
|
||||
current_patch_version = 5
|
||||
from worlds.Files import AutoPatchRegister, APDeltaPatch
|
||||
|
||||
|
||||
class AutoPatchRegister(type):
|
||||
patch_types: Dict[str, APDeltaPatch] = {}
|
||||
file_endings: Dict[str, APDeltaPatch] = {}
|
||||
|
||||
def __new__(cls, name: str, bases, dct: Dict[str, Any]):
|
||||
# construct class
|
||||
new_class = super().__new__(cls, name, bases, dct)
|
||||
if "game" in dct:
|
||||
AutoPatchRegister.patch_types[dct["game"]] = new_class
|
||||
if not dct["patch_file_ending"]:
|
||||
raise Exception(f"Need an expected file ending for {name}")
|
||||
AutoPatchRegister.file_endings[dct["patch_file_ending"]] = new_class
|
||||
return new_class
|
||||
|
||||
@staticmethod
|
||||
def get_handler(file: str) -> Optional[type(APDeltaPatch)]:
|
||||
for file_ending, handler in AutoPatchRegister.file_endings.items():
|
||||
if file.endswith(file_ending):
|
||||
return handler
|
||||
|
||||
|
||||
class APContainer:
|
||||
"""A zipfile containing at least archipelago.json"""
|
||||
version: int = current_patch_version
|
||||
compression_level: int = 9
|
||||
compression_method: int = zipfile.ZIP_DEFLATED
|
||||
game: Optional[str] = None
|
||||
|
||||
# instance attributes:
|
||||
path: Optional[str]
|
||||
player: Optional[int]
|
||||
player_name: str
|
||||
server: str
|
||||
|
||||
def __init__(self, path: Optional[str] = None, player: Optional[int] = None,
|
||||
player_name: str = "", server: str = ""):
|
||||
self.path = path
|
||||
self.player = player
|
||||
self.player_name = player_name
|
||||
self.server = server
|
||||
|
||||
def write(self, file: Optional[Union[str, BinaryIO]] = None):
|
||||
if not self.path and not file:
|
||||
raise FileNotFoundError(f"Cannot write {self.__class__.__name__} due to no path provided.")
|
||||
with zipfile.ZipFile(file if file else self.path, "w", self.compression_method, True, self.compression_level) \
|
||||
as zf:
|
||||
if file:
|
||||
self.path = zf.filename
|
||||
self.write_contents(zf)
|
||||
|
||||
def write_contents(self, opened_zipfile: zipfile.ZipFile):
|
||||
manifest = self.get_manifest()
|
||||
try:
|
||||
manifest = json.dumps(manifest)
|
||||
except Exception as e:
|
||||
raise Exception(f"Manifest {manifest} did not convert to json.") from e
|
||||
else:
|
||||
opened_zipfile.writestr("archipelago.json", manifest)
|
||||
|
||||
def read(self, file: Optional[Union[str, BinaryIO]] = None):
|
||||
"""Read data into patch object. file can be file-like, such as an outer zip file's stream."""
|
||||
if not self.path and not file:
|
||||
raise FileNotFoundError(f"Cannot read {self.__class__.__name__} due to no path provided.")
|
||||
with zipfile.ZipFile(file if file else self.path, "r") as zf:
|
||||
if file:
|
||||
self.path = zf.filename
|
||||
self.read_contents(zf)
|
||||
|
||||
def read_contents(self, opened_zipfile: zipfile.ZipFile):
|
||||
with opened_zipfile.open("archipelago.json", "r") as f:
|
||||
manifest = json.load(f)
|
||||
if manifest["compatible_version"] > self.version:
|
||||
raise Exception(f"File (version: {manifest['compatible_version']}) too new "
|
||||
f"for this handler (version: {self.version})")
|
||||
self.player = manifest["player"]
|
||||
self.server = manifest["server"]
|
||||
self.player_name = manifest["player_name"]
|
||||
|
||||
def get_manifest(self) -> dict:
|
||||
return {
|
||||
"server": self.server, # allow immediate connection to server in multiworld. Empty string otherwise
|
||||
"player": self.player,
|
||||
"player_name": self.player_name,
|
||||
"game": self.game,
|
||||
# minimum version of patch system expected for patching to be successful
|
||||
"compatible_version": 4,
|
||||
"version": current_patch_version,
|
||||
}
|
||||
|
||||
|
||||
class APDeltaPatch(APContainer, metaclass=AutoPatchRegister):
|
||||
"""An APContainer that additionally has delta.bsdiff4
|
||||
containing a delta patch to get the desired file, often a rom."""
|
||||
|
||||
hash = Optional[str] # base checksum of source file
|
||||
patch_file_ending: str = ""
|
||||
delta: Optional[bytes] = None
|
||||
result_file_ending: str = ".sfc"
|
||||
source_data: bytes
|
||||
|
||||
def __init__(self, *args, patched_path: str = "", **kwargs):
|
||||
self.patched_path = patched_path
|
||||
super(APDeltaPatch, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_manifest(self) -> dict:
|
||||
manifest = super(APDeltaPatch, self).get_manifest()
|
||||
manifest["base_checksum"] = self.hash
|
||||
manifest["result_file_ending"] = self.result_file_ending
|
||||
manifest["patch_file_ending"] = self.patch_file_ending
|
||||
return manifest
|
||||
|
||||
@classmethod
|
||||
def get_source_data(cls) -> bytes:
|
||||
"""Get Base data"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@classmethod
|
||||
def get_source_data_with_cache(cls) -> bytes:
|
||||
if not hasattr(cls, "source_data"):
|
||||
cls.source_data = cls.get_source_data()
|
||||
return cls.source_data
|
||||
|
||||
def write_contents(self, opened_zipfile: zipfile.ZipFile):
|
||||
super(APDeltaPatch, self).write_contents(opened_zipfile)
|
||||
# write Delta
|
||||
opened_zipfile.writestr("delta.bsdiff4",
|
||||
bsdiff4.diff(self.get_source_data_with_cache(), open(self.patched_path, "rb").read()),
|
||||
compress_type=zipfile.ZIP_STORED) # bsdiff4 is a format with integrated compression
|
||||
|
||||
def read_contents(self, opened_zipfile: zipfile.ZipFile):
|
||||
super(APDeltaPatch, self).read_contents(opened_zipfile)
|
||||
self.delta = opened_zipfile.read("delta.bsdiff4")
|
||||
|
||||
def patch(self, target: str):
|
||||
"""Base + Delta -> Patched"""
|
||||
if not self.delta:
|
||||
self.read()
|
||||
result = bsdiff4.patch(self.get_source_data_with_cache(), self.delta)
|
||||
with open(target, "wb") as f:
|
||||
f.write(result)
|
||||
|
||||
|
||||
# legacy patch handling follows:
|
||||
GAME_ALTTP = "A Link to the Past"
|
||||
GAME_SM = "Super Metroid"
|
||||
GAME_SOE = "Secret of Evermore"
|
||||
GAME_SMZ3 = "SMZ3"
|
||||
GAME_DKC3 = "Donkey Kong Country 3"
|
||||
supported_games = {"A Link to the Past", "Super Metroid", "Secret of Evermore", "SMZ3", "Donkey Kong Country 3"}
|
||||
|
||||
preferred_endings = {
|
||||
GAME_ALTTP: "apbp",
|
||||
GAME_SM: "apm3",
|
||||
GAME_SOE: "apsoe",
|
||||
GAME_SMZ3: "apsmz",
|
||||
GAME_DKC3: "apdkc3"
|
||||
}
|
||||
GAME_SMW = "Super Mario World"
|
||||
|
||||
|
||||
def generate_yaml(patch: bytes, metadata: Optional[dict] = None, game: str = GAME_ALTTP) -> bytes:
|
||||
if game == GAME_ALTTP:
|
||||
from worlds.alttp.Rom import LTTPJPN10HASH as HASH
|
||||
elif game == GAME_SM:
|
||||
from worlds.sm.Rom import SMJUHASH as HASH
|
||||
elif game == GAME_SOE:
|
||||
from worlds.soe.Patch import USHASH as HASH
|
||||
elif game == GAME_SMZ3:
|
||||
from worlds.alttp.Rom import LTTPJPN10HASH as ALTTPHASH
|
||||
from worlds.sm.Rom import SMJUHASH as SMHASH
|
||||
HASH = ALTTPHASH + SMHASH
|
||||
elif game == GAME_DKC3:
|
||||
from worlds.dkc3.Rom import USHASH as HASH
|
||||
else:
|
||||
raise RuntimeError(f"Selected game {game} for base rom not found.")
|
||||
|
||||
patch = yaml.dump({"meta": metadata,
|
||||
"patch": patch,
|
||||
"game": game,
|
||||
# minimum version of patch system expected for patching to be successful
|
||||
"compatible_version": 3,
|
||||
"version": current_patch_version,
|
||||
"base_checksum": HASH})
|
||||
return patch.encode(encoding="utf-8-sig")
|
||||
class RomMeta(TypedDict):
|
||||
server: str
|
||||
player: Optional[int]
|
||||
player_name: str
|
||||
|
||||
|
||||
def generate_patch(rom: bytes, metadata: Optional[dict] = None, game: str = GAME_ALTTP) -> bytes:
|
||||
if metadata is None:
|
||||
metadata = {}
|
||||
patch = bsdiff4.diff(get_base_rom_data(game), rom)
|
||||
return generate_yaml(patch, metadata, game)
|
||||
|
||||
|
||||
def create_patch_file(rom_file_to_patch: str, server: str = "", destination: str = None,
|
||||
player: int = 0, player_name: str = "", game: str = GAME_ALTTP) -> str:
|
||||
meta = {"server": server, # allow immediate connection to server in multiworld. Empty string otherwise
|
||||
"player_id": player,
|
||||
"player_name": player_name}
|
||||
bytes = generate_patch(load_bytes(rom_file_to_patch),
|
||||
meta,
|
||||
game)
|
||||
target = destination if destination else os.path.splitext(rom_file_to_patch)[0] + (
|
||||
".apbp" if game == GAME_ALTTP
|
||||
else ".apsmz" if game == GAME_SMZ3
|
||||
else ".apdkc3" if game == GAME_DKC3
|
||||
else ".apm3")
|
||||
write_lzma(bytes, target)
|
||||
return target
|
||||
|
||||
|
||||
def create_rom_bytes(patch_file: str, ignore_version: bool = False) -> Tuple[dict, str, bytearray]:
|
||||
data = Utils.parse_yaml(lzma.decompress(load_bytes(patch_file)).decode("utf-8-sig"))
|
||||
game_name = data["game"]
|
||||
if not ignore_version and data["compatible_version"] > current_patch_version:
|
||||
raise RuntimeError("Patch file is incompatible with this patcher, likely an update is required.")
|
||||
patched_data = bsdiff4.patch(get_base_rom_data(game_name), data["patch"])
|
||||
rom_hash = patched_data[int(0x7FC0):int(0x7FD5)]
|
||||
data["meta"]["hash"] = "".join(chr(x) for x in rom_hash)
|
||||
target = os.path.splitext(patch_file)[0] + ".sfc"
|
||||
return data["meta"], target, patched_data
|
||||
|
||||
|
||||
def get_base_rom_data(game: str):
|
||||
if game == GAME_ALTTP:
|
||||
from worlds.alttp.Rom import get_base_rom_bytes
|
||||
elif game == "alttp": # old version for A Link to the Past
|
||||
from worlds.alttp.Rom import get_base_rom_bytes
|
||||
elif game == GAME_SM:
|
||||
from worlds.sm.Rom import get_base_rom_bytes
|
||||
elif game == GAME_SOE:
|
||||
from worlds.soe.Patch import get_base_rom_path
|
||||
get_base_rom_bytes = lambda: bytes(read_rom(open(get_base_rom_path(), "rb")))
|
||||
elif game == GAME_SMZ3:
|
||||
from worlds.smz3.Rom import get_base_rom_bytes
|
||||
elif game == GAME_DKC3:
|
||||
from worlds.dkc3.Rom import get_base_rom_bytes
|
||||
else:
|
||||
raise RuntimeError("Selected game for base rom not found.")
|
||||
return get_base_rom_bytes()
|
||||
|
||||
|
||||
def create_rom_file(patch_file: str) -> Tuple[dict, str]:
|
||||
def create_rom_file(patch_file: str) -> Tuple[RomMeta, str]:
|
||||
auto_handler = AutoPatchRegister.get_handler(patch_file)
|
||||
if auto_handler:
|
||||
handler: APDeltaPatch = auto_handler(patch_file)
|
||||
@@ -269,171 +36,10 @@ def create_rom_file(patch_file: str) -> Tuple[dict, str]:
|
||||
return {"server": handler.server,
|
||||
"player": handler.player,
|
||||
"player_name": handler.player_name}, target
|
||||
else:
|
||||
data, target, patched_data = create_rom_bytes(patch_file)
|
||||
with open(target, "wb") as f:
|
||||
f.write(patched_data)
|
||||
return data, target
|
||||
|
||||
|
||||
def update_patch_data(patch_data: bytes, server: str = "") -> bytes:
|
||||
data = Utils.parse_yaml(lzma.decompress(patch_data).decode("utf-8-sig"))
|
||||
data["meta"]["server"] = server
|
||||
bytes = generate_yaml(data["patch"], data["meta"], data["game"])
|
||||
return lzma.compress(bytes)
|
||||
|
||||
|
||||
def load_bytes(path: str) -> bytes:
|
||||
with open(path, "rb") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def write_lzma(data: bytes, path: str):
|
||||
with lzma.LZMAFile(path, 'wb') as f:
|
||||
f.write(data)
|
||||
|
||||
|
||||
def read_rom(stream, strip_header=True) -> bytearray:
|
||||
"""Reads rom into bytearray and optionally strips off any smc header"""
|
||||
buffer = bytearray(stream.read())
|
||||
if strip_header and len(buffer) % 0x400 == 0x200:
|
||||
return buffer[0x200:]
|
||||
return buffer
|
||||
raise NotImplementedError(f"No Handler for {patch_file} found.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
host = Utils.get_public_ipv4()
|
||||
options = Utils.get_options()['server_options']
|
||||
if options['host']:
|
||||
host = options['host']
|
||||
|
||||
address = f"{host}:{options['port']}"
|
||||
ziplock = threading.Lock()
|
||||
print(f"Host for patches to be created is {address}")
|
||||
with concurrent.futures.ThreadPoolExecutor() as pool:
|
||||
for rom in sys.argv:
|
||||
try:
|
||||
if rom.endswith(".sfc"):
|
||||
print(f"Creating patch for {rom}")
|
||||
result = pool.submit(create_patch_file, rom, address)
|
||||
result.add_done_callback(lambda task: print(f"Created patch {task.result()}"))
|
||||
|
||||
elif rom.endswith(".apbp"):
|
||||
print(f"Applying patch {rom}")
|
||||
data, target = create_rom_file(rom)
|
||||
#romfile, adjusted = Utils.get_adjuster_settings(target)
|
||||
adjuster_settings = Utils.get_adjuster_settings(GAME_ALTTP)
|
||||
adjusted = False
|
||||
if adjuster_settings:
|
||||
import pprint
|
||||
from worlds.alttp.Rom import get_base_rom_path
|
||||
adjuster_settings.rom = target
|
||||
adjuster_settings.baserom = get_base_rom_path()
|
||||
adjuster_settings.world = None
|
||||
whitelist = {"music", "menuspeed", "heartbeep", "heartcolor", "ow_palettes", "quickswap",
|
||||
"uw_palettes", "sprite", "sword_palettes", "shield_palettes", "hud_palettes",
|
||||
"reduceflashing", "deathlink"}
|
||||
printed_options = {name: value for name, value in vars(adjuster_settings).items() if name in whitelist}
|
||||
if hasattr(adjuster_settings, "sprite_pool"):
|
||||
sprite_pool = {}
|
||||
for sprite in getattr(adjuster_settings, "sprite_pool"):
|
||||
if sprite in sprite_pool:
|
||||
sprite_pool[sprite] += 1
|
||||
else:
|
||||
sprite_pool[sprite] = 1
|
||||
if sprite_pool:
|
||||
printed_options["sprite_pool"] = sprite_pool
|
||||
|
||||
adjust_wanted = str('no')
|
||||
if not hasattr(adjuster_settings, 'auto_apply') or 'ask' in adjuster_settings.auto_apply:
|
||||
adjust_wanted = input(f"Last used adjuster settings were found. Would you like to apply these? \n"
|
||||
f"{pprint.pformat(printed_options)}\n"
|
||||
f"Enter yes, no, always or never: ")
|
||||
if adjuster_settings.auto_apply == 'never': # never adjust, per user request
|
||||
adjust_wanted = 'no'
|
||||
elif adjuster_settings.auto_apply == 'always':
|
||||
adjust_wanted = 'yes'
|
||||
|
||||
if adjust_wanted and "never" in adjust_wanted:
|
||||
adjuster_settings.auto_apply = 'never'
|
||||
Utils.persistent_store("adjuster", GAME_ALTTP, adjuster_settings)
|
||||
|
||||
elif adjust_wanted and "always" in adjust_wanted:
|
||||
adjuster_settings.auto_apply = 'always'
|
||||
Utils.persistent_store("adjuster", GAME_ALTTP, adjuster_settings)
|
||||
|
||||
if adjust_wanted and adjust_wanted.startswith("y"):
|
||||
if hasattr(adjuster_settings, "sprite_pool"):
|
||||
from LttPAdjuster import AdjusterWorld
|
||||
adjuster_settings.world = AdjusterWorld(getattr(adjuster_settings, "sprite_pool"))
|
||||
|
||||
adjusted = True
|
||||
import LttPAdjuster
|
||||
_, romfile = LttPAdjuster.adjust(adjuster_settings)
|
||||
|
||||
if hasattr(adjuster_settings, "world"):
|
||||
delattr(adjuster_settings, "world")
|
||||
else:
|
||||
adjusted = False
|
||||
if adjusted:
|
||||
try:
|
||||
shutil.move(romfile, target)
|
||||
romfile = target
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(f"Created rom {romfile if adjusted else target}.")
|
||||
if 'server' in data:
|
||||
Utils.persistent_store("servers", data['hash'], data['server'])
|
||||
print(f"Host is {data['server']}")
|
||||
elif rom.endswith(".apm3"):
|
||||
print(f"Applying patch {rom}")
|
||||
data, target = create_rom_file(rom)
|
||||
print(f"Created rom {target}.")
|
||||
if 'server' in data:
|
||||
Utils.persistent_store("servers", data['hash'], data['server'])
|
||||
print(f"Host is {data['server']}")
|
||||
elif rom.endswith(".apsmz"):
|
||||
print(f"Applying patch {rom}")
|
||||
data, target = create_rom_file(rom)
|
||||
print(f"Created rom {target}.")
|
||||
if 'server' in data:
|
||||
Utils.persistent_store("servers", data['hash'], data['server'])
|
||||
print(f"Host is {data['server']}")
|
||||
elif rom.endswith(".apdkc3"):
|
||||
print(f"Applying patch {rom}")
|
||||
data, target = create_rom_file(rom)
|
||||
print(f"Created rom {target}.")
|
||||
if 'server' in data:
|
||||
Utils.persistent_store("servers", data['hash'], data['server'])
|
||||
print(f"Host is {data['server']}")
|
||||
|
||||
elif rom.endswith(".zip"):
|
||||
print(f"Updating host in patch files contained in {rom}")
|
||||
|
||||
|
||||
def _handle_zip_file_entry(zfinfo: zipfile.ZipInfo, server: str):
|
||||
data = zfr.read(zfinfo)
|
||||
if zfinfo.filename.endswith(".apbp") or \
|
||||
zfinfo.filename.endswith(".apm3") or \
|
||||
zfinfo.filename.endswith(".apdkc3"):
|
||||
data = update_patch_data(data, server)
|
||||
with ziplock:
|
||||
zfw.writestr(zfinfo, data)
|
||||
return zfinfo.filename
|
||||
|
||||
|
||||
futures = []
|
||||
with zipfile.ZipFile(rom, "r") as zfr:
|
||||
updated_zip = os.path.splitext(rom)[0] + "_updated.zip"
|
||||
with zipfile.ZipFile(updated_zip, "w", compression=zipfile.ZIP_DEFLATED,
|
||||
compresslevel=9) as zfw:
|
||||
for zfname in zfr.namelist():
|
||||
futures.append(pool.submit(_handle_zip_file_entry, zfr.getinfo(zfname), address))
|
||||
for future in futures:
|
||||
print(f"File {future.result()} added to {os.path.split(updated_zip)[1]}")
|
||||
|
||||
except:
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
input("Press enter to close.")
|
||||
for file in sys.argv[1:]:
|
||||
meta_data, result_file = create_rom_file(file)
|
||||
print(f"Patch with meta-data {meta_data} was written to {result_file}")
|
||||
|
||||
@@ -28,6 +28,7 @@ Currently, the following games are supported:
|
||||
* Starcraft 2: Wings of Liberty
|
||||
* Donkey Kong Country 3
|
||||
* Dark Souls 3
|
||||
* Super Mario World
|
||||
|
||||
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
|
||||
|
||||
32
SNIClient.py
32
SNIClient.py
@@ -15,10 +15,13 @@ import typing
|
||||
|
||||
from json import loads, dumps
|
||||
|
||||
from Utils import init_logging, messagebox
|
||||
# CommonClient import first to trigger ModuleUpdater
|
||||
from CommonClient import CommonContext, server_loop, ClientCommandProcessor, gui_enabled, get_base_parser
|
||||
|
||||
import Utils
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_logging("SNIClient", exception_logger="Client")
|
||||
Utils.init_logging("SNIClient", exception_logger="Client")
|
||||
|
||||
import colorama
|
||||
import websockets
|
||||
@@ -28,9 +31,8 @@ from worlds.alttp import Regions, Shops
|
||||
from worlds.alttp.Rom import ROM_PLAYER_LIMIT
|
||||
from worlds.sm.Rom import ROM_PLAYER_LIMIT as SM_ROM_PLAYER_LIMIT
|
||||
from worlds.smz3.Rom import ROM_PLAYER_LIMIT as SMZ3_ROM_PLAYER_LIMIT
|
||||
import Utils
|
||||
from CommonClient import CommonContext, server_loop, ClientCommandProcessor, gui_enabled, get_base_parser
|
||||
from Patch import GAME_ALTTP, GAME_SM, GAME_SMZ3, GAME_DKC3
|
||||
from Patch import GAME_ALTTP, GAME_SM, GAME_SMZ3, GAME_DKC3, GAME_SMW
|
||||
|
||||
|
||||
snes_logger = logging.getLogger("SNES")
|
||||
|
||||
@@ -236,6 +238,10 @@ async def deathlink_kill_player(ctx: Context):
|
||||
snes_buffered_write(ctx, WRAM_START + 0x0A50, bytes([255])) # deal 255 of damage at next opportunity
|
||||
if not ctx.death_link_allow_survive:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x09D6, bytes([0, 0])) # set current reserve to 0
|
||||
elif ctx.game == GAME_SMW:
|
||||
from worlds.smw.Client import deathlink_kill_player as smw_deathlink_kill_player
|
||||
await smw_deathlink_kill_player(ctx)
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
@@ -1041,6 +1047,9 @@ async def game_watcher(ctx: Context):
|
||||
|
||||
from worlds.dkc3.Client import dkc3_rom_init
|
||||
init_handled = await dkc3_rom_init(ctx)
|
||||
if not init_handled:
|
||||
from worlds.smw.Client import smw_rom_init
|
||||
init_handled = await smw_rom_init(ctx)
|
||||
if not init_handled:
|
||||
game_name = await snes_read(ctx, SM_ROMNAME_START, 5)
|
||||
if game_name is None:
|
||||
@@ -1299,6 +1308,9 @@ async def game_watcher(ctx: Context):
|
||||
elif ctx.game == GAME_DKC3:
|
||||
from worlds.dkc3.Client import dkc3_game_watcher
|
||||
await dkc3_game_watcher(ctx)
|
||||
elif ctx.game == GAME_SMW:
|
||||
from worlds.smw.Client import smw_game_watcher
|
||||
await smw_game_watcher(ctx)
|
||||
|
||||
|
||||
async def run_game(romfile):
|
||||
@@ -1326,20 +1338,18 @@ async def main():
|
||||
try:
|
||||
meta, romfile = Patch.create_rom_file(args.diff_file)
|
||||
except Exception as e:
|
||||
messagebox('Error', str(e), True)
|
||||
Utils.messagebox('Error', str(e), True)
|
||||
raise
|
||||
if "server" in meta:
|
||||
args.connect = meta["server"]
|
||||
args.connect = meta["server"]
|
||||
logging.info(f"Wrote rom file to {romfile}")
|
||||
if args.diff_file.endswith(".apsoe"):
|
||||
import webbrowser
|
||||
webbrowser.open("http://www.evermizer.com/apclient/" +
|
||||
(f"#server={meta['server']}" if "server" in meta else ""))
|
||||
webbrowser.open(f"http://www.evermizer.com/apclient/#server={meta['server']}")
|
||||
logging.info("Starting Evermizer Client in your Browser...")
|
||||
import time
|
||||
time.sleep(3)
|
||||
sys.exit()
|
||||
elif args.diff_file.endswith((".apbp", ".apz3", ".aplttp")):
|
||||
elif args.diff_file.endswith(".aplttp"):
|
||||
adjustedromfile, adjusted = get_alttp_settings(romfile)
|
||||
asyncio.create_task(run_game(adjustedromfile if adjusted else romfile))
|
||||
else:
|
||||
|
||||
@@ -12,21 +12,9 @@ import typing
|
||||
import queue
|
||||
from pathlib import Path
|
||||
|
||||
import nest_asyncio
|
||||
import sc2
|
||||
from sc2.bot_ai import BotAI
|
||||
from sc2.data import Race
|
||||
from sc2.main import run_game
|
||||
from sc2.player import Bot
|
||||
|
||||
import NetUtils
|
||||
from MultiServer import mark_raw
|
||||
# CommonClient import first to trigger ModuleUpdater
|
||||
from CommonClient import CommonContext, server_loop, ClientCommandProcessor, gui_enabled, get_base_parser
|
||||
from Utils import init_logging, is_windows
|
||||
from worlds.sc2wol import SC2WoLWorld
|
||||
from worlds.sc2wol.Items import lookup_id_to_name, item_table, ItemData, type_flaggroups
|
||||
from worlds.sc2wol.Locations import SC2WOL_LOC_ID_OFFSET
|
||||
from worlds.sc2wol.MissionTables import lookup_id_to_mission
|
||||
from worlds.sc2wol.Regions import MissionInfo
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_logging("SC2Client", exception_logger="Client")
|
||||
@@ -34,10 +22,21 @@ if __name__ == "__main__":
|
||||
logger = logging.getLogger("Client")
|
||||
sc2_logger = logging.getLogger("Starcraft2")
|
||||
|
||||
import colorama
|
||||
import nest_asyncio
|
||||
import sc2
|
||||
from sc2.bot_ai import BotAI
|
||||
from sc2.data import Race
|
||||
from sc2.main import run_game
|
||||
from sc2.player import Bot
|
||||
from worlds.sc2wol import SC2WoLWorld
|
||||
from worlds.sc2wol.Items import lookup_id_to_name, item_table, ItemData, type_flaggroups
|
||||
from worlds.sc2wol.Locations import SC2WOL_LOC_ID_OFFSET
|
||||
from worlds.sc2wol.MissionTables import lookup_id_to_mission
|
||||
from worlds.sc2wol.Regions import MissionInfo
|
||||
|
||||
from NetUtils import ClientStatus, RawJSONtoTextParser
|
||||
from CommonClient import CommonContext, server_loop, ClientCommandProcessor, gui_enabled, get_base_parser
|
||||
import colorama
|
||||
from NetUtils import ClientStatus, NetworkItem, RawJSONtoTextParser
|
||||
from MultiServer import mark_raw
|
||||
|
||||
nest_asyncio.apply()
|
||||
max_bonus: int = 8
|
||||
@@ -357,8 +356,9 @@ class SC2Context(CommonContext):
|
||||
|
||||
self.ui = SC2Manager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
Builder.load_file(Utils.local_path(os.path.dirname(SC2WoLWorld.__file__), "Starcraft2.kv"))
|
||||
import pkgutil
|
||||
data = pkgutil.get_data(SC2WoLWorld.__module__, "Starcraft2.kv").decode()
|
||||
Builder.load_string(data)
|
||||
|
||||
async def shutdown(self):
|
||||
await super(SC2Context, self).shutdown()
|
||||
@@ -440,8 +440,8 @@ wol_default_categories = [
|
||||
]
|
||||
|
||||
|
||||
def calculate_items(items: typing.List[NetUtils.NetworkItem]) -> typing.List[int]:
|
||||
network_item: NetUtils.NetworkItem
|
||||
def calculate_items(items: typing.List[NetworkItem]) -> typing.List[int]:
|
||||
network_item: NetworkItem
|
||||
accumulators: typing.List[int] = [0 for _ in type_flaggroups]
|
||||
|
||||
for network_item in items:
|
||||
|
||||
31
Utils.py
31
Utils.py
@@ -11,6 +11,8 @@ import io
|
||||
import collections
|
||||
import importlib
|
||||
import logging
|
||||
from typing import BinaryIO
|
||||
|
||||
from yaml import load, load_all, dump, SafeLoader
|
||||
|
||||
try:
|
||||
@@ -217,8 +219,11 @@ def get_public_ipv6() -> str:
|
||||
return ip
|
||||
|
||||
|
||||
OptionsType = typing.Dict[str, typing.Dict[str, typing.Any]]
|
||||
|
||||
|
||||
@cache_argsless
|
||||
def get_default_options() -> dict:
|
||||
def get_default_options() -> OptionsType:
|
||||
# Refer to host.yaml for comments as to what all these options mean.
|
||||
options = {
|
||||
"general_options": {
|
||||
@@ -285,12 +290,17 @@ def get_default_options() -> dict:
|
||||
"sni": "SNI",
|
||||
"rom_start": True,
|
||||
},
|
||||
"smw_options": {
|
||||
"rom_file": "Super Mario World (USA).sfc",
|
||||
"sni": "SNI",
|
||||
"rom_start": True,
|
||||
},
|
||||
}
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def update_options(src: dict, dest: dict, filename: str, keys: list) -> dict:
|
||||
def update_options(src: dict, dest: dict, filename: str, keys: list) -> OptionsType:
|
||||
for key, value in src.items():
|
||||
new_keys = keys.copy()
|
||||
new_keys.append(key)
|
||||
@@ -310,9 +320,9 @@ def update_options(src: dict, dest: dict, filename: str, keys: list) -> dict:
|
||||
|
||||
|
||||
@cache_argsless
|
||||
def get_options() -> dict:
|
||||
def get_options() -> OptionsType:
|
||||
filenames = ("options.yaml", "host.yaml")
|
||||
locations = []
|
||||
locations: typing.List[str] = []
|
||||
if os.path.join(os.getcwd()) != local_path():
|
||||
locations += filenames # use files from cwd only if it's not the local_path
|
||||
locations += [user_path(filename) for filename in filenames]
|
||||
@@ -353,7 +363,7 @@ def persistent_load() -> typing.Dict[str, dict]:
|
||||
return storage
|
||||
|
||||
|
||||
def get_adjuster_settings(game_name: str):
|
||||
def get_adjuster_settings(game_name: str) -> typing.Dict[str, typing.Any]:
|
||||
adjuster_settings = persistent_load().get("adjuster", {}).get(game_name, {})
|
||||
return adjuster_settings
|
||||
|
||||
@@ -392,7 +402,8 @@ class RestrictedUnpickler(pickle.Unpickler):
|
||||
# Options and Plando are unpickled by WebHost -> Generate
|
||||
if module == "worlds.generic" and name in {"PlandoItem", "PlandoConnection"}:
|
||||
return getattr(self.generic_properties_module, name)
|
||||
if module.endswith("Options"):
|
||||
# pep 8 specifies that modules should have "all-lowercase names" (options, not Options)
|
||||
if module.lower().endswith("options"):
|
||||
if module == "Options":
|
||||
mod = self.options_module
|
||||
else:
|
||||
@@ -623,3 +634,11 @@ def title_sorted(data: typing.Sequence, key=None, ignore: typing.Set = frozenset
|
||||
else:
|
||||
return element.lower()
|
||||
return sorted(data, key=lambda i: sorter(key(i)) if key else sorter(i))
|
||||
|
||||
|
||||
def read_snes_rom(stream: BinaryIO, strip_header: bool = True) -> bytearray:
|
||||
"""Reads rom into bytearray and optionally strips off any smc header"""
|
||||
buffer = bytearray(stream.read())
|
||||
if strip_header and len(buffer) % 0x400 == 0x200:
|
||||
return buffer[0x200:]
|
||||
return buffer
|
||||
|
||||
@@ -10,7 +10,6 @@ from flask_compress import Compress
|
||||
from werkzeug.routing import BaseConverter
|
||||
|
||||
from Utils import title_sorted
|
||||
from .models import *
|
||||
|
||||
UPLOAD_FOLDER = os.path.relpath('uploads')
|
||||
LOGS_FOLDER = os.path.relpath('logs')
|
||||
@@ -73,8 +72,10 @@ def register():
|
||||
"""Import submodules, triggering their registering on flask routing.
|
||||
Note: initializes worlds subsystem."""
|
||||
# has automatic patch integration
|
||||
import Patch
|
||||
app.jinja_env.filters['supports_apdeltapatch'] = lambda game_name: game_name in Patch.AutoPatchRegister.patch_types
|
||||
import worlds.AutoWorld
|
||||
import worlds.Files
|
||||
app.jinja_env.filters['supports_apdeltapatch'] = lambda game_name: \
|
||||
game_name in worlds.Files.AutoPatchRegister.patch_types
|
||||
|
||||
from WebHostLib.customserver import run_server_process
|
||||
# to trigger app routing picking up on it
|
||||
|
||||
@@ -7,7 +7,8 @@ from . import api_endpoints
|
||||
from flask import request, session, url_for
|
||||
from pony.orm import commit
|
||||
|
||||
from WebHostLib import app, Generation, STATE_QUEUED, Seed, STATE_ERROR
|
||||
from WebHostLib import app
|
||||
from WebHostLib.models import Generation, STATE_QUEUED, Seed, STATE_ERROR
|
||||
from WebHostLib.check import get_yaml_data, roll_options
|
||||
from WebHostLib.generate import get_meta
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ from io import BytesIO
|
||||
from flask import send_file, Response, render_template
|
||||
from pony.orm import select
|
||||
|
||||
from Patch import update_patch_data, preferred_endings, AutoPatchRegister
|
||||
from WebHostLib import app, Slot, Room, Seed, cache
|
||||
from worlds.Files import AutoPatchRegister
|
||||
from . import app, cache
|
||||
from .models import Slot, Room, Seed
|
||||
|
||||
|
||||
@app.route("/dl_patch/<suuid:room_id>/<int:patch_id>")
|
||||
@@ -41,12 +42,7 @@ def download_patch(room_id, patch_id):
|
||||
new_file.seek(0)
|
||||
return send_file(new_file, as_attachment=True, download_name=fname)
|
||||
else:
|
||||
patch_data = update_patch_data(patch.data, server=f"{app.config['PATCH_TARGET']}:{last_port}")
|
||||
patch_data = BytesIO(patch_data)
|
||||
|
||||
fname = f"P{patch.player_id}_{patch.player_name}_{app.jinja_env.filters['suuid'](room_id)}." \
|
||||
f"{preferred_endings[patch.game]}"
|
||||
return send_file(patch_data, as_attachment=True, download_name=fname)
|
||||
return "Old Patch file, no longer compatible."
|
||||
|
||||
|
||||
@app.route("/dl_spoiler/<suuid:seed_id>")
|
||||
|
||||
@@ -151,7 +151,7 @@ def favicon():
|
||||
|
||||
@app.route('/discord')
|
||||
def discord():
|
||||
return redirect("https://discord.gg/archipelago")
|
||||
return redirect("https://discord.gg/8Z65BR2")
|
||||
|
||||
|
||||
@app.route('/datapackage')
|
||||
|
||||
@@ -64,7 +64,10 @@ def create():
|
||||
|
||||
for game_name, world in AutoWorldRegister.world_types.items():
|
||||
|
||||
all_options = {**Options.per_game_common_options, **world.option_definitions}
|
||||
all_options: typing.Dict[str, Options.AssembleOptions] = {
|
||||
**Options.per_game_common_options,
|
||||
**world.option_definitions
|
||||
}
|
||||
with open(local_path("WebHostLib", "templates", "options.yaml")) as f:
|
||||
file_data = f.read()
|
||||
res = Template(file_data).render(
|
||||
|
||||
@@ -46,7 +46,7 @@ the website is not required to generate them.
|
||||
## How do I get started?
|
||||
|
||||
If you are ready to start randomizing games, or want to start playing your favorite randomizer with others, please join
|
||||
our discord server at the [Archipelago Discord](https://discord.gg/archipelago). There are always people ready to answer
|
||||
our discord server at the [Archipelago Discord](https://discord.gg/8Z65BR2). There are always people ready to answer
|
||||
any questions you might have.
|
||||
|
||||
## What are some common terms I should know?
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<td></td>
|
||||
{% endif %}
|
||||
<td><img src="{{ icons['Elevator Keycard'] }}" class="{{ 'acquired' if 'Elevator Keycard' in acquired_items }}" title="Elevator Keycard" /></td>
|
||||
{% if 'FacebookMode' in options %}
|
||||
{% if 'EyeSpy' in options %}
|
||||
<td><img src="{{ icons['Oculus Ring'] }}" class="{{ 'acquired' if 'Oculus Ring' in acquired_items }}" title="Oculus Ring" /></td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
|
||||
@@ -8,7 +8,8 @@ import datetime
|
||||
from uuid import UUID
|
||||
|
||||
from worlds.alttp import Items
|
||||
from WebHostLib import app, cache, Room
|
||||
from . import app, cache
|
||||
from .models import Room
|
||||
from Utils import restricted_loads
|
||||
from worlds import lookup_any_item_id_to_name, lookup_any_location_id_to_name
|
||||
from MultiServer import Context
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import typing
|
||||
import zipfile
|
||||
import lzma
|
||||
import json
|
||||
import base64
|
||||
import MultiServer
|
||||
@@ -10,9 +9,10 @@ from io import BytesIO
|
||||
from flask import request, flash, redirect, url_for, session, render_template
|
||||
from pony.orm import flush, select
|
||||
|
||||
from WebHostLib import app, Seed, Room, Slot
|
||||
from Utils import parse_yaml, VersionException, __version__
|
||||
from Patch import preferred_endings, AutoPatchRegister
|
||||
from . import app
|
||||
from .models import Seed, Room, Slot
|
||||
from Utils import VersionException, __version__
|
||||
from worlds.Files import AutoPatchRegister
|
||||
from NetUtils import NetworkSlot, SlotType
|
||||
|
||||
banned_zip_contents = (".sfc",)
|
||||
@@ -22,7 +22,7 @@ def upload_zip_to_db(zfile: zipfile.ZipFile, owner=None, meta={"race": False}, s
|
||||
if not owner:
|
||||
owner = session["_id"]
|
||||
infolist = zfile.infolist()
|
||||
slots = set()
|
||||
slots: typing.Set[Slot] = set()
|
||||
spoiler = ""
|
||||
multidata = None
|
||||
for file in infolist:
|
||||
@@ -38,17 +38,6 @@ def upload_zip_to_db(zfile: zipfile.ZipFile, owner=None, meta={"race": False}, s
|
||||
player_name=patch.player_name,
|
||||
player_id=patch.player,
|
||||
game=patch.game))
|
||||
elif file.filename.endswith(tuple(preferred_endings.values())):
|
||||
data = zfile.open(file, "r").read()
|
||||
yaml_data = parse_yaml(lzma.decompress(data).decode("utf-8-sig"))
|
||||
if yaml_data["version"] < 2:
|
||||
return "Old format cannot be uploaded (outdated .apbp)"
|
||||
metadata = yaml_data["meta"]
|
||||
|
||||
slots.add(Slot(data=data,
|
||||
player_name=metadata["player_name"],
|
||||
player_id=metadata["player_id"],
|
||||
game=yaml_data["game"]))
|
||||
|
||||
elif file.filename.endswith(".apmc"):
|
||||
data = zfile.open(file, "r").read()
|
||||
|
||||
Binary file not shown.
BIN
data/basepatch.bsdiff4
Normal file
BIN
data/basepatch.bsdiff4
Normal file
Binary file not shown.
@@ -221,7 +221,7 @@ Starting with version 4 of the APBP format, this is a ZIP file containing metada
|
||||
files required by the game / patching process. For ROM-based games the ZIP will include a `delta.bsdiff4` which is the
|
||||
bsdiff between the original and the randomized ROM.
|
||||
|
||||
To make using APBP easy, they can be generated by inheriting from `Patch.APDeltaPatch`.
|
||||
To make using APBP easy, they can be generated by inheriting from `worlds.Files.APDeltaPatch`.
|
||||
|
||||
### Mod files
|
||||
Games which support modding will usually just let you drag and drop the mod’s files into a folder somewhere.
|
||||
@@ -230,7 +230,7 @@ They can either be generic and modify the game using a seed or `slot_data` from
|
||||
generated per seed.
|
||||
|
||||
If the mod is generated by AP and is installed from a ZIP file, it may be possible to include APBP metadata for easy
|
||||
integration into the Webhost by inheriting from `Patch.APContainer`.
|
||||
integration into the Webhost by inheriting from `worlds.Files.APContainer`.
|
||||
|
||||
|
||||
## Archipelago Integration
|
||||
|
||||
@@ -21,7 +21,7 @@ There are also a number of community-supported libraries available that implemen
|
||||
| | [Archipelago SNIClient](https://github.com/ArchipelagoMW/Archipelago/blob/main/SNIClient.py) | For Super Nintendo Game Support; Utilizes [SNI](https://github.com/alttpo/sni). |
|
||||
| JVM (Java / Kotlin) | [Archipelago.MultiClient.Java](https://github.com/ArchipelagoMW/Archipelago.MultiClient.Java) | |
|
||||
| .NET (C# / C++ / F# / VB.NET) | [Archipelago.MultiClient.Net](https://www.nuget.org/packages/Archipelago.MultiClient.Net) | |
|
||||
| C++ | [apclientpp](https://github.com/black-sliver/apclientpp) | almost-header-only |
|
||||
| C++ | [apclientpp](https://github.com/black-sliver/apclientpp) | header-only |
|
||||
| | [APCpp](https://github.com/N00byKing/APCpp) | CMake |
|
||||
| JavaScript / TypeScript | [archipelago.js](https://www.npmjs.com/package/archipelago.js) | Browser and Node.js Supported |
|
||||
| Haxe | [hxArchipelago](https://lib.haxe.org/p/hxArchipelago) | |
|
||||
@@ -371,7 +371,7 @@ Used to write data to the server's data storage, that data can then be shared ac
|
||||
| ------ | ----- | ------ |
|
||||
| key | str | The key to manipulate. |
|
||||
| default | any | The default value to use in case the key has no value on the server. |
|
||||
| want_reply | bool | If set, the server will send a [SetReply](#SetReply) response back to the client. |
|
||||
| want_reply | bool | If true, the server will send a [SetReply](#SetReply) response back to the client. |
|
||||
| operations | list\[[DataStorageOperation](#DataStorageOperation)\] | Operations to apply to the value, multiple operations can be present and they will be executed in order of appearance. |
|
||||
|
||||
Additional arguments sent in this package will also be added to the [SetReply](#SetReply) package it triggers.
|
||||
|
||||
@@ -16,6 +16,10 @@ Then run any of the starting point scripts, like Generate.py, and the included M
|
||||
required modules and after pressing enter proceed to install everything automatically.
|
||||
After this, you should be able to run the programs.
|
||||
|
||||
* With yaml(s) in the `Players` folder, `Generate.py` will generate the multiworld archive.
|
||||
* `MultiServer.py`, with the filename of the generated archive as a command line parameter, will host the multiworld locally.
|
||||
* `--log_network` is a command line parameter useful for debugging.
|
||||
|
||||
|
||||
## Windows
|
||||
|
||||
|
||||
@@ -138,3 +138,12 @@ dkc3_options:
|
||||
# True for operating system default program
|
||||
# Alternatively, a path to a program to open the .sfc file with
|
||||
rom_start: true
|
||||
smw_options:
|
||||
# File name of the SMW US rom
|
||||
rom_file: "Super Mario World (USA).sfc"
|
||||
# Set this to your SNI folder location if you want the MultiClient to attempt an auto start, does nothing if not found
|
||||
sni: "SNI"
|
||||
# Set this to false to never autostart a rom (such as after patching)
|
||||
# True for operating system default program
|
||||
# Alternatively, a path to a program to open the .sfc file with
|
||||
rom_start: true
|
||||
|
||||
@@ -55,6 +55,7 @@ Name: "core"; Description: "Core Files"; Types: full hosting playing
|
||||
Name: "generator"; Description: "Generator"; Types: full hosting
|
||||
Name: "generator/sm"; Description: "Super Metroid ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 3145728; Flags: disablenouninstallwarning
|
||||
Name: "generator/dkc3"; Description: "Donkey Kong Country 3 ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 3145728; Flags: disablenouninstallwarning
|
||||
Name: "generator/smw"; Description: "Super Mario World ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 3145728; Flags: disablenouninstallwarning
|
||||
Name: "generator/soe"; Description: "Secret of Evermore ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 3145728; Flags: disablenouninstallwarning
|
||||
Name: "generator/lttp"; Description: "A Link to the Past ROM Setup and Enemizer"; Types: full hosting; ExtraDiskSpaceRequired: 5191680
|
||||
Name: "generator/oot"; Description: "Ocarina of Time ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 100663296; Flags: disablenouninstallwarning
|
||||
@@ -64,6 +65,7 @@ Name: "client/sni"; Description: "SNI Client"; Types: full playing
|
||||
Name: "client/sni/lttp"; Description: "SNI Client - A Link to the Past Patch Setup"; Types: full playing; Flags: disablenouninstallwarning
|
||||
Name: "client/sni/sm"; Description: "SNI Client - Super Metroid Patch Setup"; Types: full playing; Flags: disablenouninstallwarning
|
||||
Name: "client/sni/dkc3"; Description: "SNI Client - Donkey Kong Country 3 Patch Setup"; Types: full playing; Flags: disablenouninstallwarning
|
||||
Name: "client/sni/smw"; Description: "SNI Client - Super Mario World Patch Setup"; Types: full playing; Flags: disablenouninstallwarning
|
||||
Name: "client/factorio"; Description: "Factorio"; Types: full playing
|
||||
Name: "client/minecraft"; Description: "Minecraft"; Types: full playing; ExtraDiskSpaceRequired: 226894278
|
||||
Name: "client/oot"; Description: "Ocarina of Time"; Types: full playing
|
||||
@@ -79,6 +81,7 @@ NAME: "{app}"; Flags: setntfscompression; Permissions: everyone-modify users-mod
|
||||
Source: "{code:GetROMPath}"; DestDir: "{app}"; DestName: "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"; Flags: external; Components: client/sni/lttp or generator/lttp
|
||||
Source: "{code:GetSMROMPath}"; DestDir: "{app}"; DestName: "Super Metroid (JU).sfc"; Flags: external; Components: client/sni/sm or generator/sm
|
||||
Source: "{code:GetDKC3ROMPath}"; DestDir: "{app}"; DestName: "Donkey Kong Country 3 - Dixie Kong's Double Trouble! (USA) (En,Fr).sfc"; Flags: external; Components: client/sni/dkc3 or generator/dkc3
|
||||
Source: "{code:GetSMWROMPath}"; DestDir: "{app}"; DestName: "Super Mario World (USA).sfc"; Flags: external; Components: client/sni/smw or generator/smw
|
||||
Source: "{code:GetSoEROMPath}"; DestDir: "{app}"; DestName: "Secret of Evermore (USA).sfc"; Flags: external; Components: generator/soe
|
||||
Source: "{code:GetOoTROMPath}"; DestDir: "{app}"; DestName: "The Legend of Zelda - Ocarina of Time.z64"; Flags: external; Components: client/oot or generator/oot
|
||||
Source: "{#source_path}\*"; Excludes: "*.sfc, *.log, data\sprites\alttpr, SNI, EnemizerCLI, Archipelago*.exe"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
@@ -151,6 +154,11 @@ Root: HKCR; Subkey: "{#MyAppName}dkc3patch"; ValueData: "Arc
|
||||
Root: HKCR; Subkey: "{#MyAppName}dkc3patch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}dkc3patch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/sni
|
||||
|
||||
Root: HKCR; Subkey: ".apsmw"; ValueData: "{#MyAppName}smwpatch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}smwpatch"; ValueData: "Archipelago Super Mario World Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}smwpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}smwpatch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/sni
|
||||
|
||||
Root: HKCR; Subkey: ".apsmz3"; ValueData: "{#MyAppName}smz3patch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}smz3patch"; ValueData: "Archipelago SMZ3 Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}smz3patch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Components: client/sni
|
||||
@@ -217,6 +225,9 @@ var SMRomFilePage: TInputFileWizardPage;
|
||||
var dkc3rom: string;
|
||||
var DKC3RomFilePage: TInputFileWizardPage;
|
||||
|
||||
var smwrom: string;
|
||||
var SMWRomFilePage: TInputFileWizardPage;
|
||||
|
||||
var soerom: string;
|
||||
var SoERomFilePage: TInputFileWizardPage;
|
||||
|
||||
@@ -308,6 +319,8 @@ begin
|
||||
Result := not (SMROMFilePage.Values[0] = '')
|
||||
else if (assigned(DKC3ROMFilePage)) and (CurPageID = DKC3ROMFilePage.ID) then
|
||||
Result := not (DKC3ROMFilePage.Values[0] = '')
|
||||
else if (assigned(SMWROMFilePage)) and (CurPageID = SMWROMFilePage.ID) then
|
||||
Result := not (SMWROMFilePage.Values[0] = '')
|
||||
else if (assigned(SoEROMFilePage)) and (CurPageID = SoEROMFilePage.ID) then
|
||||
Result := not (SoEROMFilePage.Values[0] = '')
|
||||
else if (assigned(OoTROMFilePage)) and (CurPageID = OoTROMFilePage.ID) then
|
||||
@@ -364,6 +377,22 @@ begin
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function GetSMWROMPath(Param: string): string;
|
||||
begin
|
||||
if Length(smwrom) > 0 then
|
||||
Result := smwrom
|
||||
else if Assigned(SMWRomFilePage) then
|
||||
begin
|
||||
R := CompareStr(GetSNESMD5OfFile(SMWROMFilePage.Values[0]), 'cdd3c8c37322978ca8669b34bc89c804')
|
||||
if R <> 0 then
|
||||
MsgBox('Super Mario World ROM validation failed. Very likely wrong file.', mbInformation, MB_OK);
|
||||
|
||||
Result := SMWROMFilePage.Values[0]
|
||||
end
|
||||
else
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function GetSoEROMPath(Param: string): string;
|
||||
begin
|
||||
if Length(soerom) > 0 then
|
||||
@@ -412,6 +441,10 @@ begin
|
||||
if Length(dkc3rom) = 0 then
|
||||
DKC3RomFilePage:= AddRomPage('Donkey Kong Country 3 - Dixie Kong''s Double Trouble! (USA) (En,Fr).sfc');
|
||||
|
||||
smwrom := CheckRom('Super Mario World (USA).sfc', 'cdd3c8c37322978ca8669b34bc89c804');
|
||||
if Length(smwrom) = 0 then
|
||||
SMWRomFilePage:= AddRomPage('Super Mario World (USA).sfc');
|
||||
|
||||
soerom := CheckRom('Secret of Evermore (USA).sfc', '6e9c94511d04fac6e0a1e582c170be3a');
|
||||
if Length(soerom) = 0 then
|
||||
SoEROMFilePage:= AddRomPage('Secret of Evermore (USA).sfc');
|
||||
@@ -427,6 +460,8 @@ begin
|
||||
Result := not (WizardIsComponentSelected('client/sni/sm') or WizardIsComponentSelected('generator/sm'));
|
||||
if (assigned(DKC3ROMFilePage)) and (PageID = DKC3ROMFilePage.ID) then
|
||||
Result := not (WizardIsComponentSelected('client/sni/dkc3') or WizardIsComponentSelected('generator/dkc3'));
|
||||
if (assigned(SMWROMFilePage)) and (PageID = SMWROMFilePage.ID) then
|
||||
Result := not (WizardIsComponentSelected('client/sni/smw') or WizardIsComponentSelected('generator/smw'));
|
||||
if (assigned(SoEROMFilePage)) and (PageID = SoEROMFilePage.ID) then
|
||||
Result := not (WizardIsComponentSelected('generator/soe'));
|
||||
if (assigned(OoTROMFilePage)) and (PageID = OoTROMFilePage.ID) then
|
||||
|
||||
@@ -20,7 +20,7 @@ class TestBase(unittest.TestCase):
|
||||
for location in world.get_locations():
|
||||
if location.name not in excluded:
|
||||
with self.subTest("Location should be reached", location=location):
|
||||
self.assertTrue(location.can_reach(state))
|
||||
self.assertTrue(location.can_reach(state), f"{location.name} unreachable")
|
||||
|
||||
with self.subTest("Completion Condition"):
|
||||
self.assertTrue(world.can_beat_game(state))
|
||||
|
||||
@@ -23,10 +23,8 @@ class TestMinor(TestBase):
|
||||
self.world.set_default_common_options()
|
||||
self.world.logic[1] = "minorglitches"
|
||||
self.world.difficulty_requirements[1] = difficulties['normal']
|
||||
create_regions(self.world, 1)
|
||||
create_dungeons(self.world, 1)
|
||||
create_shops(self.world, 1)
|
||||
link_entrances(self.world, 1)
|
||||
self.world.worlds[1].er_seed = 0
|
||||
self.world.worlds[1].create_regions()
|
||||
self.world.worlds[1].create_items()
|
||||
self.world.required_medallions[1] = ['Ether', 'Quake']
|
||||
self.world.itempool.extend(get_dungeon_item_pool(self.world))
|
||||
|
||||
@@ -24,10 +24,8 @@ class TestVanillaOWG(TestBase):
|
||||
self.world.set_default_common_options()
|
||||
self.world.difficulty_requirements[1] = difficulties['normal']
|
||||
self.world.logic[1] = "owglitches"
|
||||
create_regions(self.world, 1)
|
||||
create_dungeons(self.world, 1)
|
||||
create_shops(self.world, 1)
|
||||
link_entrances(self.world, 1)
|
||||
self.world.worlds[1].er_seed = 0
|
||||
self.world.worlds[1].create_regions()
|
||||
self.world.worlds[1].create_items()
|
||||
self.world.required_medallions[1] = ['Ether', 'Quake']
|
||||
self.world.itempool.extend(get_dungeon_item_pool(self.world))
|
||||
|
||||
@@ -22,10 +22,8 @@ class TestVanilla(TestBase):
|
||||
self.world.set_default_common_options()
|
||||
self.world.logic[1] = "noglitches"
|
||||
self.world.difficulty_requirements[1] = difficulties['normal']
|
||||
create_regions(self.world, 1)
|
||||
create_dungeons(self.world, 1)
|
||||
create_shops(self.world, 1)
|
||||
link_entrances(self.world, 1)
|
||||
self.world.worlds[1].er_seed = 0
|
||||
self.world.worlds[1].create_regions()
|
||||
self.world.worlds[1].create_items()
|
||||
self.world.required_medallions[1] = ['Ether', 'Quake']
|
||||
self.world.itempool.extend(get_dungeon_item_pool(self.world))
|
||||
|
||||
@@ -3,9 +3,9 @@ from __future__ import annotations
|
||||
import logging
|
||||
import sys
|
||||
import pathlib
|
||||
from typing import Dict, FrozenSet, Set, Tuple, List, Optional, TextIO, Any, Callable, Union, TYPE_CHECKING
|
||||
from typing import Dict, FrozenSet, Set, Tuple, List, Optional, TextIO, Any, Callable, Type, Union, TYPE_CHECKING
|
||||
|
||||
from Options import Option
|
||||
from Options import AssembleOptions
|
||||
from BaseClasses import CollectionState
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class AutoWorldRegister(type):
|
||||
world_types: Dict[str, type(World)] = {}
|
||||
world_types: Dict[str, Type[World]] = {}
|
||||
|
||||
def __new__(mcs, name: str, bases: Tuple[type, ...], dct: Dict[str, Any]) -> AutoWorldRegister:
|
||||
if "web" in dct:
|
||||
@@ -120,7 +120,7 @@ class World(metaclass=AutoWorldRegister):
|
||||
"""A World object encompasses a game's Items, Locations, Rules and additional data or functionality required.
|
||||
A Game should have its own subclass of World in which it defines the required data structures."""
|
||||
|
||||
option_definitions: Dict[str, Option[Any]] = {} # link your Options mapping
|
||||
option_definitions: Dict[str, AssembleOptions] = {} # link your Options mapping
|
||||
game: str # name the game
|
||||
topology_present: bool = False # indicate if world type has any meaningful layout/pathing
|
||||
|
||||
@@ -229,7 +229,8 @@ class World(metaclass=AutoWorldRegister):
|
||||
pass
|
||||
|
||||
def post_fill(self) -> None:
|
||||
"""Optional Method that is called after regular fill. Can be used to do adjustments before output generation."""
|
||||
"""Optional Method that is called after regular fill. Can be used to do adjustments before output generation.
|
||||
This happens before progression balancing, so the items may not be in their final locations yet."""
|
||||
|
||||
def generate_output(self, output_directory: str) -> None:
|
||||
"""This method gets called from a threadpool, do not use world.random here.
|
||||
@@ -237,7 +238,9 @@ class World(metaclass=AutoWorldRegister):
|
||||
pass
|
||||
|
||||
def fill_slot_data(self) -> Dict[str, Any]: # json of WebHostLib.models.Slot
|
||||
"""Fill in the slot_data field in the Connected network package."""
|
||||
"""Fill in the `slot_data` field in the `Connected` network package.
|
||||
This is a way the generator can give custom data to the client.
|
||||
The client will receive this as JSON in the `Connected` response."""
|
||||
return {}
|
||||
|
||||
def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]):
|
||||
|
||||
156
worlds/Files.py
Normal file
156
worlds/Files.py
Normal file
@@ -0,0 +1,156 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import zipfile
|
||||
|
||||
from typing import ClassVar, Dict, Tuple, Any, Optional, Union, BinaryIO
|
||||
|
||||
import bsdiff4
|
||||
|
||||
|
||||
class AutoPatchRegister(type):
|
||||
patch_types: ClassVar[Dict[str, AutoPatchRegister]] = {}
|
||||
file_endings: ClassVar[Dict[str, AutoPatchRegister]] = {}
|
||||
|
||||
def __new__(mcs, name: str, bases: Tuple[type, ...], dct: Dict[str, Any]) -> AutoPatchRegister:
|
||||
# construct class
|
||||
new_class = super().__new__(mcs, name, bases, dct)
|
||||
if "game" in dct:
|
||||
AutoPatchRegister.patch_types[dct["game"]] = new_class
|
||||
if not dct["patch_file_ending"]:
|
||||
raise Exception(f"Need an expected file ending for {name}")
|
||||
AutoPatchRegister.file_endings[dct["patch_file_ending"]] = new_class
|
||||
return new_class
|
||||
|
||||
@staticmethod
|
||||
def get_handler(file: str) -> Optional[AutoPatchRegister]:
|
||||
for file_ending, handler in AutoPatchRegister.file_endings.items():
|
||||
if file.endswith(file_ending):
|
||||
return handler
|
||||
return None
|
||||
|
||||
|
||||
current_patch_version: int = 5
|
||||
|
||||
|
||||
class APContainer:
|
||||
"""A zipfile containing at least archipelago.json"""
|
||||
version: int = current_patch_version
|
||||
compression_level: int = 9
|
||||
compression_method: int = zipfile.ZIP_DEFLATED
|
||||
game: Optional[str] = None
|
||||
|
||||
# instance attributes:
|
||||
path: Optional[str]
|
||||
player: Optional[int]
|
||||
player_name: str
|
||||
server: str
|
||||
|
||||
def __init__(self, path: Optional[str] = None, player: Optional[int] = None,
|
||||
player_name: str = "", server: str = ""):
|
||||
self.path = path
|
||||
self.player = player
|
||||
self.player_name = player_name
|
||||
self.server = server
|
||||
|
||||
def write(self, file: Optional[Union[str, BinaryIO]] = None) -> None:
|
||||
zip_file = file if file else self.path
|
||||
if not zip_file:
|
||||
raise FileNotFoundError(f"Cannot write {self.__class__.__name__} due to no path provided.")
|
||||
with zipfile.ZipFile(zip_file, "w", self.compression_method, True, self.compression_level) \
|
||||
as zf:
|
||||
if file:
|
||||
self.path = zf.filename
|
||||
self.write_contents(zf)
|
||||
|
||||
def write_contents(self, opened_zipfile: zipfile.ZipFile) -> None:
|
||||
manifest = self.get_manifest()
|
||||
try:
|
||||
manifest_str = json.dumps(manifest)
|
||||
except Exception as e:
|
||||
raise Exception(f"Manifest {manifest} did not convert to json.") from e
|
||||
else:
|
||||
opened_zipfile.writestr("archipelago.json", manifest_str)
|
||||
|
||||
def read(self, file: Optional[Union[str, BinaryIO]] = None) -> None:
|
||||
"""Read data into patch object. file can be file-like, such as an outer zip file's stream."""
|
||||
zip_file = file if file else self.path
|
||||
if not zip_file:
|
||||
raise FileNotFoundError(f"Cannot read {self.__class__.__name__} due to no path provided.")
|
||||
with zipfile.ZipFile(zip_file, "r") as zf:
|
||||
if file:
|
||||
self.path = zf.filename
|
||||
self.read_contents(zf)
|
||||
|
||||
def read_contents(self, opened_zipfile: zipfile.ZipFile) -> None:
|
||||
with opened_zipfile.open("archipelago.json", "r") as f:
|
||||
manifest = json.load(f)
|
||||
if manifest["compatible_version"] > self.version:
|
||||
raise Exception(f"File (version: {manifest['compatible_version']}) too new "
|
||||
f"for this handler (version: {self.version})")
|
||||
self.player = manifest["player"]
|
||||
self.server = manifest["server"]
|
||||
self.player_name = manifest["player_name"]
|
||||
|
||||
def get_manifest(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"server": self.server, # allow immediate connection to server in multiworld. Empty string otherwise
|
||||
"player": self.player,
|
||||
"player_name": self.player_name,
|
||||
"game": self.game,
|
||||
# minimum version of patch system expected for patching to be successful
|
||||
"compatible_version": 4,
|
||||
"version": current_patch_version,
|
||||
}
|
||||
|
||||
|
||||
class APDeltaPatch(APContainer, metaclass=AutoPatchRegister):
|
||||
"""An APContainer that additionally has delta.bsdiff4
|
||||
containing a delta patch to get the desired file, often a rom."""
|
||||
|
||||
hash: Optional[str] # base checksum of source file
|
||||
patch_file_ending: str = ""
|
||||
delta: Optional[bytes] = None
|
||||
result_file_ending: str = ".sfc"
|
||||
source_data: bytes
|
||||
|
||||
def __init__(self, *args: Any, patched_path: str = "", **kwargs: Any) -> None:
|
||||
self.patched_path = patched_path
|
||||
super(APDeltaPatch, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_manifest(self) -> Dict[str, Any]:
|
||||
manifest = super(APDeltaPatch, self).get_manifest()
|
||||
manifest["base_checksum"] = self.hash
|
||||
manifest["result_file_ending"] = self.result_file_ending
|
||||
manifest["patch_file_ending"] = self.patch_file_ending
|
||||
return manifest
|
||||
|
||||
@classmethod
|
||||
def get_source_data(cls) -> bytes:
|
||||
"""Get Base data"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@classmethod
|
||||
def get_source_data_with_cache(cls) -> bytes:
|
||||
if not hasattr(cls, "source_data"):
|
||||
cls.source_data = cls.get_source_data()
|
||||
return cls.source_data
|
||||
|
||||
def write_contents(self, opened_zipfile: zipfile.ZipFile):
|
||||
super(APDeltaPatch, self).write_contents(opened_zipfile)
|
||||
# write Delta
|
||||
opened_zipfile.writestr("delta.bsdiff4",
|
||||
bsdiff4.diff(self.get_source_data_with_cache(), open(self.patched_path, "rb").read()),
|
||||
compress_type=zipfile.ZIP_STORED) # bsdiff4 is a format with integrated compression
|
||||
|
||||
def read_contents(self, opened_zipfile: zipfile.ZipFile):
|
||||
super(APDeltaPatch, self).read_contents(opened_zipfile)
|
||||
self.delta = opened_zipfile.read("delta.bsdiff4")
|
||||
|
||||
def patch(self, target: str):
|
||||
"""Base + Delta -> Patched"""
|
||||
if not self.delta:
|
||||
self.read()
|
||||
result = bsdiff4.patch(self.get_source_data_with_cache(), self.delta)
|
||||
with open(target, "wb") as f:
|
||||
f.write(result)
|
||||
@@ -1,7 +1,9 @@
|
||||
import importlib
|
||||
import zipimport
|
||||
import os
|
||||
import sys
|
||||
import typing
|
||||
import warnings
|
||||
import zipimport
|
||||
|
||||
folder = os.path.dirname(__file__)
|
||||
|
||||
@@ -39,7 +41,14 @@ world_sources.sort()
|
||||
for world_source in world_sources:
|
||||
if world_source.is_zip:
|
||||
importer = zipimport.zipimporter(os.path.join(folder, world_source.path))
|
||||
importer.load_module(world_source.path.split(".", 1)[0])
|
||||
spec = importer.find_spec(world_source.path.split(".", 1)[0])
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
mod.__package__ = f"worlds.{mod.__package__}"
|
||||
mod.__name__ = f"worlds.{mod.__name__}"
|
||||
sys.modules[mod.__name__] = mod
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", message="__package__ != __spec__.parent")
|
||||
importer.exec_module(mod)
|
||||
else:
|
||||
importlib.import_module(f".{world_source.path}", "worlds")
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import Utils
|
||||
from Patch import read_rom
|
||||
import worlds.AutoWorld
|
||||
import worlds.Files
|
||||
|
||||
LTTPJPN10HASH = '03a63945398191337e896e5771f77173'
|
||||
RANDOMIZERBASEHASH = '9952c2a3ec1b421e408df0d20c8f0c7f'
|
||||
ROM_PLAYER_LIMIT = 255
|
||||
LTTPJPN10HASH: str = "03a63945398191337e896e5771f77173"
|
||||
RANDOMIZERBASEHASH: str = "9952c2a3ec1b421e408df0d20c8f0c7f"
|
||||
ROM_PLAYER_LIMIT: int = 255
|
||||
|
||||
import io
|
||||
import json
|
||||
@@ -34,7 +35,7 @@ from worlds.alttp.Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts
|
||||
DeathMountain_texts, \
|
||||
LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, \
|
||||
SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names
|
||||
from Utils import local_path, user_path, int16_as_bytes, int32_as_bytes, snes_to_pc, is_frozen, parse_yaml
|
||||
from Utils import local_path, user_path, int16_as_bytes, int32_as_bytes, snes_to_pc, is_frozen, parse_yaml, read_snes_rom
|
||||
from worlds.alttp.Items import ItemFactory, item_table, item_name_groups, progression_items
|
||||
from worlds.alttp.EntranceShuffle import door_addresses
|
||||
from worlds.alttp.Options import smallkey_shuffle
|
||||
@@ -57,13 +58,13 @@ class LocalRom(object):
|
||||
self.orig_buffer = None
|
||||
|
||||
with open(file, 'rb') as stream:
|
||||
self.buffer = read_rom(stream)
|
||||
self.buffer = read_snes_rom(stream)
|
||||
if patch:
|
||||
self.patch_base_rom()
|
||||
self.orig_buffer = self.buffer.copy()
|
||||
if vanillaRom:
|
||||
with open(vanillaRom, 'rb') as vanillaStream:
|
||||
self.orig_buffer = read_rom(vanillaStream)
|
||||
self.orig_buffer = read_snes_rom(vanillaStream)
|
||||
|
||||
def read_byte(self, address: int) -> int:
|
||||
return self.buffer[address]
|
||||
@@ -123,29 +124,24 @@ class LocalRom(object):
|
||||
return expected == buffermd5.hexdigest()
|
||||
|
||||
def patch_base_rom(self):
|
||||
if os.path.isfile(local_path('basepatch.sfc')):
|
||||
with open(local_path('basepatch.sfc'), 'rb') as stream:
|
||||
if os.path.isfile(user_path('basepatch.sfc')):
|
||||
with open(user_path('basepatch.sfc'), 'rb') as stream:
|
||||
buffer = bytearray(stream.read())
|
||||
|
||||
if self.verify(buffer):
|
||||
self.buffer = buffer
|
||||
if not os.path.exists(local_path('data', 'basepatch.apbp')):
|
||||
Patch.create_patch_file(local_path('basepatch.sfc'))
|
||||
return
|
||||
|
||||
if not os.path.isfile(local_path('data', 'basepatch.apbp')):
|
||||
raise RuntimeError('Base patch unverified. Unable to continue.')
|
||||
with open(local_path("data", "basepatch.bsdiff4"), "rb") as f:
|
||||
delta = f.read()
|
||||
|
||||
if os.path.isfile(local_path('data', 'basepatch.apbp')):
|
||||
_, target, buffer = Patch.create_rom_bytes(local_path('data', 'basepatch.apbp'), ignore_version=True)
|
||||
if self.verify(buffer):
|
||||
self.buffer = bytearray(buffer)
|
||||
with open(user_path('basepatch.sfc'), 'wb') as stream:
|
||||
stream.write(buffer)
|
||||
return
|
||||
raise RuntimeError('Base patch unverified. Unable to continue.')
|
||||
|
||||
raise RuntimeError('Could not find Base Patch. Unable to continue.')
|
||||
buffer = bsdiff4.patch(get_base_rom_bytes(), delta)
|
||||
if self.verify(buffer):
|
||||
self.buffer = bytearray(buffer)
|
||||
with open(user_path('basepatch.sfc'), 'wb') as stream:
|
||||
stream.write(buffer)
|
||||
return
|
||||
raise RuntimeError('Base patch unverified. Unable to continue.')
|
||||
|
||||
def write_crc(self):
|
||||
crc = (sum(self.buffer[:0x7FDC] + self.buffer[0x7FE0:]) + 0x01FE) & 0xFFFF
|
||||
@@ -544,7 +540,7 @@ class Sprite():
|
||||
|
||||
def get_vanilla_sprite_data(self):
|
||||
file_name = get_base_rom_path()
|
||||
base_rom_bytes = bytes(read_rom(open(file_name, "rb")))
|
||||
base_rom_bytes = bytes(read_snes_rom(open(file_name, "rb")))
|
||||
Sprite.sprite = base_rom_bytes[0x80000:0x87000]
|
||||
Sprite.palette = base_rom_bytes[0xDD308:0xDD380]
|
||||
Sprite.glove_palette = base_rom_bytes[0xDEDF5:0xDEDF9]
|
||||
@@ -2906,7 +2902,7 @@ hash_alphabet = [
|
||||
]
|
||||
|
||||
|
||||
class LttPDeltaPatch(Patch.APDeltaPatch):
|
||||
class LttPDeltaPatch(worlds.Files.APDeltaPatch):
|
||||
hash = LTTPJPN10HASH
|
||||
game = "A Link to the Past"
|
||||
patch_file_ending = ".aplttp"
|
||||
@@ -2920,7 +2916,7 @@ def get_base_rom_bytes(file_name: str = "") -> bytes:
|
||||
base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None)
|
||||
if not base_rom_bytes:
|
||||
file_name = get_base_rom_path(file_name)
|
||||
base_rom_bytes = bytes(read_rom(open(file_name, "rb")))
|
||||
base_rom_bytes = bytes(read_snes_rom(open(file_name, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(base_rom_bytes)
|
||||
|
||||
@@ -7,7 +7,7 @@ import typing
|
||||
import Utils
|
||||
from BaseClasses import Item, CollectionState, Tutorial
|
||||
from .Dungeons import create_dungeons
|
||||
from .EntranceShuffle import link_entrances, link_inverted_entrances, plando_connect
|
||||
from .EntranceShuffle import link_entrances, link_inverted_entrances, plando_connect, indirect_connections
|
||||
from .InvertedRegions import create_inverted_regions, mark_dark_world_regions
|
||||
from .ItemPool import generate_itempool, difficulties
|
||||
from .Items import item_init_table, item_name_groups, item_table, GetBeemizerItem
|
||||
@@ -19,7 +19,7 @@ from .Rom import LocalRom, patch_rom, patch_race_rom, check_enemizer, patch_enem
|
||||
from .Rules import set_rules
|
||||
from .Shops import create_shops, ShopSlotFill
|
||||
from .SubClasses import ALttPItem
|
||||
from ..AutoWorld import World, WebWorld, LogicMixin
|
||||
from worlds.AutoWorld import World, WebWorld, LogicMixin
|
||||
|
||||
lttp_logger = logging.getLogger("A Link to the Past")
|
||||
|
||||
@@ -223,6 +223,10 @@ class ALTTPWorld(World):
|
||||
world.random = old_random
|
||||
plando_connect(world, player)
|
||||
|
||||
for region_name, entrance_name in indirect_connections.items():
|
||||
world.register_indirect_condition(self.world.get_region(region_name, player),
|
||||
self.world.get_entrance(entrance_name, player))
|
||||
|
||||
def collect_item(self, state: CollectionState, item: Item, remove=False):
|
||||
item_name = item.name
|
||||
if item_name.startswith('Progressive '):
|
||||
@@ -396,11 +400,7 @@ class ALTTPWorld(World):
|
||||
deathlink=world.death_link[player],
|
||||
allowcollect=world.allow_collect[player])
|
||||
|
||||
outfilepname = f'_P{player}'
|
||||
outfilepname += f"_{world.get_file_safe_player_name(player).replace(' ', '_')}" \
|
||||
if world.player_name[player] != 'Player%d' % player else ''
|
||||
|
||||
rompath = os.path.join(output_directory, f'AP_{world.seed_name}{outfilepname}.sfc')
|
||||
rompath = os.path.join(output_directory, f"{self.world.get_out_file_name_base(self.player)}.sfc")
|
||||
rom.write_to_file(rompath)
|
||||
patch = LttPDeltaPatch(os.path.splitext(rompath)[0]+LttPDeltaPatch.patch_file_ending, player=player,
|
||||
player_name=world.player_name[player], patched_path=rompath)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- [SNI](https://github.com/alttpo/sni/releases) (Integriert in Archipelago)
|
||||
- Hardware oder Software zum Laden und Abspielen von SNES Rom-Dateien fähig zu einer Internetverbindung
|
||||
- Ein Emulator, der mit SNI verbinden kann
|
||||
([snes9x Multitroid](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz),
|
||||
([snes9x rr](https://github.com/gocha/snes9x-rr/releases),
|
||||
[BizHawk](http://tasvideos.org/BizHawk.html))
|
||||
- Ein SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), oder andere kompatible Hardware
|
||||
- Die Japanische Zelda 1.0 ROM-Datei, mit folgendem Namen: `Zelda no Densetsu - Kamigami no Triforce (Japan).sfc`
|
||||
@@ -93,7 +93,7 @@ Wenn der client den Emulator automatisch gestartet hat, wird SNI ebenfalls im Hi
|
||||
Mal ist, wird möglicherweise ein Fenster angezeigt, wo man bestätigen muss, dass das Programm durch die Windows Firewall
|
||||
kommunizieren darf.
|
||||
|
||||
##### snes9x Multitroid
|
||||
##### snes9x-rr
|
||||
|
||||
1. Lade die Entsprechende ROM-Datei, wenn sie nicht schon automatisch geladen wurde.
|
||||
2. Klicke auf den Reiter "File" oben im Menü und wähle **Lua Scripting**
|
||||
|
||||
@@ -75,7 +75,7 @@ client, and will also create your ROM in the same place as your patch file.
|
||||
When the client launched automatically, SNI should have also automatically launched in the background. If this is its
|
||||
first time launching, you may be prompted to allow it to communicate through the Windows Firewall.
|
||||
|
||||
##### snes9x Multitroid
|
||||
##### snes9x-rr
|
||||
|
||||
1. Load your ROM file if it hasn't already been loaded.
|
||||
2. Click on the File menu and hover on **Lua Scripting**
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- [QUsb2Snes](https://github.com/Skarsnik/QUsb2snes/releases) (Incluido en Multiworld Utilities)
|
||||
- Hardware o software capaz de cargar y ejecutar archivos de ROM de SNES
|
||||
- Un emulador capaz de ejecutar scripts Lua
|
||||
([snes9x Multitroid](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz),
|
||||
([snes9x rr](https://github.com/gocha/snes9x-rr/releases),
|
||||
[BizHawk](http://tasvideos.org/BizHawk.html), o
|
||||
[RetroArch](https://retroarch.com?page=platforms) 1.10.1 o más nuevo). O,
|
||||
- Un flashcart SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), o otro hardware compatible
|
||||
@@ -111,13 +111,13 @@ automáticamente el cliente, y ademas creara la rom en el mismo directorio donde
|
||||
Cuando el cliente se lance automáticamente, QUsb2Snes debería haberse ejecutado también. Si es la primera vez que lo
|
||||
ejecutas, puedes ser que el firewall de Windows te pregunte si le permites la comunicación.
|
||||
|
||||
##### snes9x Multitroid
|
||||
##### snes9x-rr
|
||||
|
||||
1. Carga tu fichero de ROM, si no lo has hecho ya
|
||||
2. Abre el menu "File" y situa el raton en **Lua Scripting**
|
||||
3. Haz click en **New Lua Script Window...**
|
||||
4. En la nueva ventana, haz click en **Browse...**
|
||||
5. Navega hacia el directorio donde este situado snes9x Multitroid, entra en el directorio `lua`, y
|
||||
5. Navega hacia el directorio donde este situado snes9x-rr, entra en el directorio `lua`, y
|
||||
escoge `multibridge.lua`
|
||||
6. Observa que se ha asignado un nombre al dispositivo, y el cliente muestra "SNES Device: Connected", con el mismo
|
||||
nombre en la esquina superior izquierda.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- [QUsb2Snes](https://github.com/Skarsnik/QUsb2snes/releases) (Inclus dans les utilitaires précédents)
|
||||
- Une solution logicielle ou matérielle capable de charger et de lancer des fichiers ROM de SNES
|
||||
- Un émulateur capable d'éxécuter des scripts Lua
|
||||
([snes9x Multitroid](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz),
|
||||
([snes9x rr](https://github.com/gocha/snes9x-rr/releases),
|
||||
[BizHawk](http://tasvideos.org/BizHawk.html))
|
||||
- Un SD2SNES, [FXPak Pro](https://krikzz.com/store/home/54-fxpak-pro.html), ou une autre solution matérielle
|
||||
compatible
|
||||
@@ -112,13 +112,13 @@ Quand le client se lance automatiquement, QUsb2Snes devrait se lancer automatiqu
|
||||
c'est la première fois qu'il démarre, il vous sera peut-être demandé de l'autoriser à communiquer à travers le pare-feu
|
||||
Windows.
|
||||
|
||||
##### snes9x Multitroid
|
||||
##### snes9x-rr
|
||||
|
||||
1. Chargez votre ROM si ce n'est pas déjà fait.
|
||||
2. Cliquez sur le menu "File" et survolez l'option **Lua Scripting**
|
||||
3. Cliquez alors sur **New Lua Script Window...**
|
||||
4. Dans la nouvelle fenêtre, sélectionnez **Browse...**
|
||||
5. Dirigez vous vers le dossier où vous avez extrait snes9x Multitroid, allez dans le dossier `lua`, puis
|
||||
5. Dirigez vous vers le dossier où vous avez extrait snes9x-rr, allez dans le dossier `lua`, puis
|
||||
choisissez `multibridge.lua`
|
||||
6. Remarquez qu'un nom vous a été assigné, et que l'interface Web affiche "SNES Device: Connected", avec ce même nom
|
||||
dans le coin en haut à gauche.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Utils
|
||||
from Patch import read_rom, APDeltaPatch
|
||||
from Utils import read_snes_rom
|
||||
from worlds.Files import APDeltaPatch
|
||||
from .Locations import lookup_id_to_name, all_locations
|
||||
from .Levels import level_list, level_dict
|
||||
|
||||
@@ -440,13 +441,13 @@ class LocalRom(object):
|
||||
self.orig_buffer = None
|
||||
|
||||
with open(file, 'rb') as stream:
|
||||
self.buffer = read_rom(stream)
|
||||
self.buffer = read_snes_rom(stream)
|
||||
#if patch:
|
||||
# self.patch_rom()
|
||||
# self.orig_buffer = self.buffer.copy()
|
||||
#if vanillaRom:
|
||||
# with open(vanillaRom, 'rb') as vanillaStream:
|
||||
# self.orig_buffer = read_rom(vanillaStream)
|
||||
# self.orig_buffer = read_snes_rom(vanillaStream)
|
||||
|
||||
def read_bit(self, address: int, bit_number: int) -> bool:
|
||||
bitflag = (1 << bit_number)
|
||||
@@ -724,7 +725,7 @@ def get_base_rom_bytes(file_name: str = "") -> bytes:
|
||||
base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None)
|
||||
if not base_rom_bytes:
|
||||
file_name = get_base_rom_path(file_name)
|
||||
base_rom_bytes = bytes(read_rom(open(file_name, "rb")))
|
||||
base_rom_bytes = bytes(read_snes_rom(open(file_name, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(base_rom_bytes)
|
||||
|
||||
@@ -146,11 +146,7 @@ class DKC3World(World):
|
||||
|
||||
self.active_level_list.append(LocationName.rocket_rush_region)
|
||||
|
||||
outfilepname = f'_P{player}'
|
||||
outfilepname += f"_{world.player_name[player].replace(' ', '_')}" \
|
||||
if world.player_name[player] != 'Player%d' % player else ''
|
||||
|
||||
rompath = os.path.join(output_directory, f'AP_{world.seed_name}{outfilepname}.sfc')
|
||||
rompath = os.path.join(output_directory, f"{self.world.get_out_file_name_base(self.player)}.sfc")
|
||||
rom.write_to_file(rompath)
|
||||
self.rom_name = rom.name
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
- Hardware or software capable of loading and playing SNES ROM files
|
||||
- An emulator capable of connecting to SNI such as:
|
||||
- snes9x Multitroid
|
||||
from: [snes9x Multitroid Download](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz),
|
||||
- snes9x-rr from: [snes9x rr](https://github.com/gocha/snes9x-rr/releases),
|
||||
- BizHawk from: [BizHawk Website](http://tasvideos.org/BizHawk.html)
|
||||
- RetroArch 1.10.3 or newer from: [RetroArch Website](https://retroarch.com?page=platforms). Or,
|
||||
- An SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other
|
||||
@@ -81,7 +80,7 @@ client, and will also create your ROM in the same place as your patch file.
|
||||
When the client launched automatically, SNI should have also automatically launched in the background. If this is its
|
||||
first time launching, you may be prompted to allow it to communicate through the Windows Firewall.
|
||||
|
||||
##### snes9x Multitroid
|
||||
##### snes9x-rr
|
||||
|
||||
1. Load your ROM file if it hasn't already been loaded.
|
||||
2. Click on the File menu and hover on **Lua Scripting**
|
||||
|
||||
@@ -11,6 +11,8 @@ import shutil
|
||||
|
||||
import Utils
|
||||
import Patch
|
||||
import worlds.AutoWorld
|
||||
import worlds.Files
|
||||
from . import Options
|
||||
|
||||
from .Technologies import tech_table, recipes, free_sample_exclusions, progressive_technology_table, \
|
||||
@@ -57,7 +59,7 @@ recipe_time_ranges = {
|
||||
}
|
||||
|
||||
|
||||
class FactorioModFile(Patch.APContainer):
|
||||
class FactorioModFile(worlds.Files.APContainer):
|
||||
game = "Factorio"
|
||||
compression_method = zipfile.ZIP_DEFLATED # Factorio can't load LZMA archives
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import LocationProgressType
|
||||
from BaseClasses import LocationProgressType, MultiWorld
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
import BaseClasses
|
||||
@@ -37,14 +37,14 @@ def locality_rules(world, player: int):
|
||||
forbid_items_for_player(location, world.non_local_items[player].value, player)
|
||||
|
||||
|
||||
def exclusion_rules(world, player: int, exclude_locations: typing.Set[str]):
|
||||
def exclusion_rules(world: MultiWorld, player: int, exclude_locations: typing.Set[str]) -> None:
|
||||
for loc_name in exclude_locations:
|
||||
try:
|
||||
location = world.get_location(loc_name, player)
|
||||
except KeyError as e: # failed to find the given location. Check if it's a legitimate location
|
||||
if loc_name not in world.worlds[player].location_name_to_id:
|
||||
raise Exception(f"Unable to exclude location {loc_name} in player {player}'s world.") from e
|
||||
else:
|
||||
else:
|
||||
add_item_rule(location, lambda i: not (i.advancement or i.useful))
|
||||
location.progress_type = LocationProgressType.EXCLUDED
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ class MinecraftWorld(World):
|
||||
|
||||
def generate_output(self, output_directory: str):
|
||||
data = self._get_mc_data()
|
||||
filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_file_safe_player_name(self.player)}.apmc"
|
||||
filename = f"{self.world.get_out_file_name_base(self.player)}.apmc"
|
||||
with open(os.path.join(output_directory, filename), 'wb') as f:
|
||||
f.write(b64encode(bytes(json.dumps(data), 'utf-8')))
|
||||
|
||||
|
||||
@@ -819,7 +819,7 @@ class OOTWorld(World):
|
||||
# Seed hint RNG, used for ganon text lines also
|
||||
self.hint_rng = self.world.slot_seeds[self.player]
|
||||
|
||||
outfile_name = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_file_safe_player_name(self.player)}"
|
||||
outfile_name = self.world.get_out_file_name_base(self.player)
|
||||
rom = Rom(file=get_options()['oot_options']['rom_file'])
|
||||
if self.hints != 'none':
|
||||
buildWorldGossipHints(self)
|
||||
|
||||
@@ -27,13 +27,10 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
LocationData("Liberation Day", "Liberation Day: Fourth Statue", SC2WOL_LOC_ID_OFFSET + 104),
|
||||
LocationData("Liberation Day", "Liberation Day: Fifth Statue", SC2WOL_LOC_ID_OFFSET + 105),
|
||||
LocationData("Liberation Day", "Liberation Day: Sixth Statue", SC2WOL_LOC_ID_OFFSET + 106),
|
||||
LocationData("Liberation Day", "Beat Liberation Day", None),
|
||||
LocationData("The Outlaws", "The Outlaws: Victory", SC2WOL_LOC_ID_OFFSET + 200,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("The Outlaws", "The Outlaws: Rebel Base", SC2WOL_LOC_ID_OFFSET + 201,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("The Outlaws", "Beat The Outlaws", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Zero Hour", "Zero Hour: Victory", SC2WOL_LOC_ID_OFFSET + 300,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Zero Hour", "Zero Hour: First Group Rescued", SC2WOL_LOC_ID_OFFSET + 301),
|
||||
@@ -41,26 +38,20 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Zero Hour", "Zero Hour: Third Group Rescued", SC2WOL_LOC_ID_OFFSET + 303,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Zero Hour", "Beat Zero Hour", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Evacuation", "Evacuation: Victory", SC2WOL_LOC_ID_OFFSET + 400,
|
||||
lambda state: state._sc2wol_has_anti_air(world, player)),
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
LocationData("Evacuation", "Evacuation: First Chysalis", SC2WOL_LOC_ID_OFFSET + 401),
|
||||
LocationData("Evacuation", "Evacuation: Second Chysalis", SC2WOL_LOC_ID_OFFSET + 402,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Evacuation", "Evacuation: Third Chysalis", SC2WOL_LOC_ID_OFFSET + 403,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Evacuation", "Beat Evacuation", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
LocationData("Outbreak", "Outbreak: Victory", SC2WOL_LOC_ID_OFFSET + 500,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)),
|
||||
LocationData("Outbreak", "Outbreak: Left Infestor", SC2WOL_LOC_ID_OFFSET + 501,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)),
|
||||
LocationData("Outbreak", "Outbreak: Right Infestor", SC2WOL_LOC_ID_OFFSET + 502,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)),
|
||||
LocationData("Outbreak", "Beat Outbreak", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)),
|
||||
LocationData("Safe Haven", "Safe Haven: Victory", SC2WOL_LOC_ID_OFFSET + 600,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
@@ -73,9 +64,6 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
LocationData("Safe Haven", "Safe Haven: South Nexus", SC2WOL_LOC_ID_OFFSET + 603,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
LocationData("Safe Haven", "Beat Safe Haven", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
LocationData("Haven's Fall", "Haven's Fall: Victory", SC2WOL_LOC_ID_OFFSET + 700,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
@@ -88,9 +76,6 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
LocationData("Haven's Fall", "Haven's Fall: South Hive", SC2WOL_LOC_ID_OFFSET + 703,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
LocationData("Haven's Fall", "Beat Haven's Fall", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
LocationData("Smash and Grab", "Smash and Grab: Victory", SC2WOL_LOC_ID_OFFSET + 800,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
@@ -101,9 +86,6 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
LocationData("Smash and Grab", "Smash and Grab: Fourth Relic", SC2WOL_LOC_ID_OFFSET + 804,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_anti_air(world, player)),
|
||||
LocationData("Smash and Grab", "Beat Smash and Grab", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_anti_air(world, player)),
|
||||
LocationData("The Dig", "The Dig: Victory", SC2WOL_LOC_ID_OFFSET + 900,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_anti_air(world, player) and
|
||||
@@ -114,10 +96,6 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("The Dig", "The Dig: Right Cliff Relic", SC2WOL_LOC_ID_OFFSET + 903,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("The Dig", "Beat The Dig", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_anti_air(world, player) and
|
||||
state._sc2wol_has_heavy_defense(world, player)),
|
||||
LocationData("The Moebius Factor", "The Moebius Factor: Victory", SC2WOL_LOC_ID_OFFSET + 1000,
|
||||
lambda state: state._sc2wol_has_air(world, player) and state._sc2wol_has_anti_air(world, player)),
|
||||
LocationData("The Moebius Factor", "The Moebius Factor: South Rescue", SC2WOL_LOC_ID_OFFSET + 1003,
|
||||
@@ -132,8 +110,6 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
lambda state: state._sc2wol_able_to_rescue(world, player)),
|
||||
LocationData("The Moebius Factor", "The Moebius Factor: Brutalisk", SC2WOL_LOC_ID_OFFSET + 1008,
|
||||
lambda state: state._sc2wol_has_air(world, player)),
|
||||
LocationData("The Moebius Factor", "Beat The Moebius Factor", None,
|
||||
lambda state: state._sc2wol_has_air(world, player)),
|
||||
LocationData("Supernova", "Supernova: Victory", SC2WOL_LOC_ID_OFFSET + 1100,
|
||||
lambda state: state._sc2wol_beats_protoss_deathball(world, player)),
|
||||
LocationData("Supernova", "Supernova: West Relic", SC2WOL_LOC_ID_OFFSET + 1101),
|
||||
@@ -142,8 +118,6 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
lambda state: state._sc2wol_beats_protoss_deathball(world, player)),
|
||||
LocationData("Supernova", "Supernova: East Relic", SC2WOL_LOC_ID_OFFSET + 1104,
|
||||
lambda state: state._sc2wol_beats_protoss_deathball(world, player)),
|
||||
LocationData("Supernova", "Beat Supernova", None,
|
||||
lambda state: state._sc2wol_beats_protoss_deathball(world, player)),
|
||||
LocationData("Maw of the Void", "Maw of the Void: Victory", SC2WOL_LOC_ID_OFFSET + 1200,
|
||||
lambda state: state.has('Battlecruiser', player) or
|
||||
state._sc2wol_has_air(world, player) and
|
||||
@@ -170,19 +144,12 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
state._sc2wol_has_air(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player) and
|
||||
state.has('Science Vessel', player)),
|
||||
LocationData("Maw of the Void", "Beat Maw of the Void", None,
|
||||
lambda state: state.has('Battlecruiser', player) or
|
||||
state._sc2wol_has_air(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player) and
|
||||
state.has('Science Vessel', player)),
|
||||
LocationData("Devil's Playground", "Devil's Playground: Victory", SC2WOL_LOC_ID_OFFSET + 1300,
|
||||
lambda state: state._sc2wol_has_anti_air(world, player) and (
|
||||
state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player))),
|
||||
LocationData("Devil's Playground", "Devil's Playground: Tosh's Miners", SC2WOL_LOC_ID_OFFSET + 1301),
|
||||
LocationData("Devil's Playground", "Devil's Playground: Brutalisk", SC2WOL_LOC_ID_OFFSET + 1302,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)),
|
||||
LocationData("Devil's Playground", "Beat Devil's Playground", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) or state.has("Reaper", player)),
|
||||
LocationData("Welcome to the Jungle", "Welcome to the Jungle: Victory", SC2WOL_LOC_ID_OFFSET + 1400,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
@@ -193,28 +160,21 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
LocationData("Welcome to the Jungle", "Welcome to the Jungle: North-East Relic", SC2WOL_LOC_ID_OFFSET + 1403,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
LocationData("Welcome to the Jungle", "Beat Welcome to the Jungle", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player) and
|
||||
state._sc2wol_has_competent_anti_air(world, player)),
|
||||
LocationData("Breakout", "Breakout: Victory", SC2WOL_LOC_ID_OFFSET + 1500),
|
||||
LocationData("Breakout", "Breakout: Diamondback Prison", SC2WOL_LOC_ID_OFFSET + 1501),
|
||||
LocationData("Breakout", "Breakout: Siegetank Prison", SC2WOL_LOC_ID_OFFSET + 1502),
|
||||
LocationData("Breakout", "Beat Breakout", None),
|
||||
LocationData("Ghost of a Chance", "Ghost of a Chance: Victory", SC2WOL_LOC_ID_OFFSET + 1600),
|
||||
LocationData("Ghost of a Chance", "Ghost of a Chance: Terrazine Tank", SC2WOL_LOC_ID_OFFSET + 1601),
|
||||
LocationData("Ghost of a Chance", "Ghost of a Chance: Jorium Stockpile", SC2WOL_LOC_ID_OFFSET + 1602),
|
||||
LocationData("Ghost of a Chance", "Ghost of a Chance: First Island Spectres", SC2WOL_LOC_ID_OFFSET + 1603),
|
||||
LocationData("Ghost of a Chance", "Ghost of a Chance: Second Island Spectres", SC2WOL_LOC_ID_OFFSET + 1604),
|
||||
LocationData("Ghost of a Chance", "Ghost of a Chance: Third Island Spectres", SC2WOL_LOC_ID_OFFSET + 1605),
|
||||
LocationData("Ghost of a Chance", "Beat Ghost of a Chance", None),
|
||||
LocationData("The Great Train Robbery", "The Great Train Robbery: Victory", SC2WOL_LOC_ID_OFFSET + 1700,
|
||||
lambda state: state._sc2wol_has_train_killers(world, player) and
|
||||
state._sc2wol_has_anti_air(world, player)),
|
||||
LocationData("The Great Train Robbery", "The Great Train Robbery: North Defiler", SC2WOL_LOC_ID_OFFSET + 1701),
|
||||
LocationData("The Great Train Robbery", "The Great Train Robbery: Mid Defiler", SC2WOL_LOC_ID_OFFSET + 1702),
|
||||
LocationData("The Great Train Robbery", "The Great Train Robbery: South Defiler", SC2WOL_LOC_ID_OFFSET + 1703),
|
||||
LocationData("The Great Train Robbery", "Beat The Great Train Robbery", None,
|
||||
lambda state: state._sc2wol_has_train_killers(world, player)),
|
||||
LocationData("Cutthroat", "Cutthroat: Victory", SC2WOL_LOC_ID_OFFSET + 1800,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Cutthroat", "Cutthroat: Mira Han", SC2WOL_LOC_ID_OFFSET + 1801,
|
||||
@@ -224,10 +184,9 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
LocationData("Cutthroat", "Cutthroat: Mid Relic", SC2WOL_LOC_ID_OFFSET + 1803),
|
||||
LocationData("Cutthroat", "Cutthroat: Southwest Relic", SC2WOL_LOC_ID_OFFSET + 1804,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Cutthroat", "Beat Cutthroat", None,
|
||||
lambda state: state._sc2wol_has_common_unit(world, player)),
|
||||
LocationData("Engine of Destruction", "Engine of Destruction: Victory", SC2WOL_LOC_ID_OFFSET + 1900,
|
||||
lambda state: state._sc2wol_has_competent_anti_air(world, player)),
|
||||
lambda state: state._sc2wol_has_competent_anti_air(world, player) and
|
||||
state._sc2wol_has_common_unit(world, player) or state.has('Wraith', player)),
|
||||
LocationData("Engine of Destruction", "Engine of Destruction: Odin", SC2WOL_LOC_ID_OFFSET + 1901),
|
||||
LocationData("Engine of Destruction", "Engine of Destruction: Loki", SC2WOL_LOC_ID_OFFSET + 1902,
|
||||
lambda state: state._sc2wol_has_competent_anti_air(world, player) and
|
||||
@@ -239,9 +198,6 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
LocationData("Engine of Destruction", "Engine of Destruction: Southeast Devourer", SC2WOL_LOC_ID_OFFSET + 1905,
|
||||
lambda state: state._sc2wol_has_competent_anti_air(world, player) and
|
||||
state._sc2wol_has_common_unit(world, player) or state.has('Wraith', player)),
|
||||
LocationData("Engine of Destruction", "Beat Engine of Destruction", None,
|
||||
lambda state: state._sc2wol_has_competent_anti_air(world, player) and
|
||||
state._sc2wol_has_common_unit(world, player) or state.has('Wraith', player)),
|
||||
LocationData("Media Blitz", "Media Blitz: Victory", SC2WOL_LOC_ID_OFFSET + 2000,
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("Media Blitz", "Media Blitz: Tower 1", SC2WOL_LOC_ID_OFFSET + 2001,
|
||||
@@ -251,8 +207,6 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
LocationData("Media Blitz", "Media Blitz: Tower 3", SC2WOL_LOC_ID_OFFSET + 2003,
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("Media Blitz", "Media Blitz: Science Facility", SC2WOL_LOC_ID_OFFSET + 2004),
|
||||
LocationData("Media Blitz", "Beat Media Blitz", None,
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("Piercing the Shroud", "Piercing the Shroud: Victory", SC2WOL_LOC_ID_OFFSET + 2100,
|
||||
lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)),
|
||||
LocationData("Piercing the Shroud", "Piercing the Shroud: Holding Cell Relic", SC2WOL_LOC_ID_OFFSET + 2101),
|
||||
@@ -264,44 +218,34 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)),
|
||||
LocationData("Piercing the Shroud", "Piercing the Shroud: Brutalisk ", SC2WOL_LOC_ID_OFFSET + 2105,
|
||||
lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)),
|
||||
LocationData("Piercing the Shroud", "Beat Piercing the Shroud", None,
|
||||
lambda state: state.has_any({'Combat Shield (Marine)', 'Stabilizer Medpacks (Medic)'}, player)),
|
||||
LocationData("Whispers of Doom", "Whispers of Doom: Victory", SC2WOL_LOC_ID_OFFSET + 2200),
|
||||
LocationData("Whispers of Doom", "Whispers of Doom: First Hatchery", SC2WOL_LOC_ID_OFFSET + 2201),
|
||||
LocationData("Whispers of Doom", "Whispers of Doom: Second Hatchery", SC2WOL_LOC_ID_OFFSET + 2202),
|
||||
LocationData("Whispers of Doom", "Whispers of Doom: Third Hatchery", SC2WOL_LOC_ID_OFFSET + 2203),
|
||||
LocationData("Whispers of Doom", "Beat Whispers of Doom", None),
|
||||
LocationData("A Sinister Turn", "A Sinister Turn: Victory", SC2WOL_LOC_ID_OFFSET + 2300,
|
||||
lambda state: state._sc2wol_has_protoss_medium_units(world, player)),
|
||||
LocationData("A Sinister Turn", "A Sinister Turn: Robotics Facility", SC2WOL_LOC_ID_OFFSET + 2301),
|
||||
LocationData("A Sinister Turn", "A Sinister Turn: Dark Shrine", SC2WOL_LOC_ID_OFFSET + 2302),
|
||||
LocationData("A Sinister Turn", "A Sinister Turn: Templar Archives", SC2WOL_LOC_ID_OFFSET + 2303,
|
||||
lambda state: state._sc2wol_has_protoss_common_units(world, player)),
|
||||
LocationData("A Sinister Turn", "Beat A Sinister Turn", None,
|
||||
lambda state: state._sc2wol_has_protoss_medium_units(world, player)),
|
||||
LocationData("Echoes of the Future", "Echoes of the Future: Victory", SC2WOL_LOC_ID_OFFSET + 2400,
|
||||
lambda state: state._sc2wol_has_protoss_medium_units(world, player)),
|
||||
LocationData("Echoes of the Future", "Echoes of the Future: Close Obelisk", SC2WOL_LOC_ID_OFFSET + 2401),
|
||||
LocationData("Echoes of the Future", "Echoes of the Future: West Obelisk", SC2WOL_LOC_ID_OFFSET + 2402,
|
||||
lambda state: state._sc2wol_has_protoss_common_units(world, player)),
|
||||
LocationData("Echoes of the Future", "Beat Echoes of the Future", None,
|
||||
lambda state: state._sc2wol_has_protoss_medium_units(world, player)),
|
||||
LocationData("In Utter Darkness", "In Utter Darkness: Defeat", SC2WOL_LOC_ID_OFFSET + 2500),
|
||||
LocationData("In Utter Darkness", "In Utter Darkness: Protoss Archive", SC2WOL_LOC_ID_OFFSET + 2501,
|
||||
lambda state: state._sc2wol_has_protoss_medium_units(world, player)),
|
||||
LocationData("In Utter Darkness", "In Utter Darkness: Kills", SC2WOL_LOC_ID_OFFSET + 2502,
|
||||
lambda state: state._sc2wol_has_protoss_common_units(world, player)),
|
||||
LocationData("In Utter Darkness", "Beat In Utter Darkness", None),
|
||||
LocationData("Gates of Hell", "Gates of Hell: Victory", SC2WOL_LOC_ID_OFFSET + 2600,
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("Gates of Hell", "Gates of Hell: Large Army", SC2WOL_LOC_ID_OFFSET + 2601,
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("Gates of Hell", "Beat Gates of Hell", None),
|
||||
LocationData("Belly of the Beast", "Belly of the Beast: Victory", SC2WOL_LOC_ID_OFFSET + 2700),
|
||||
LocationData("Belly of the Beast", "Belly of the Beast: First Charge", SC2WOL_LOC_ID_OFFSET + 2701),
|
||||
LocationData("Belly of the Beast", "Belly of the Beast: Second Charge", SC2WOL_LOC_ID_OFFSET + 2702),
|
||||
LocationData("Belly of the Beast", "Belly of the Beast: Third Charge", SC2WOL_LOC_ID_OFFSET + 2703),
|
||||
LocationData("Belly of the Beast", "Beat Belly of the Beast", None),
|
||||
LocationData("Shatter the Sky", "Shatter the Sky: Victory", SC2WOL_LOC_ID_OFFSET + 2800,
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("Shatter the Sky", "Shatter the Sky: Close Coolant Tower", SC2WOL_LOC_ID_OFFSET + 2801,
|
||||
@@ -314,9 +258,15 @@ def get_locations(world: Optional[MultiWorld], player: Optional[int]) -> Tuple[L
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("Shatter the Sky", "Shatter the Sky: Leviathan", SC2WOL_LOC_ID_OFFSET + 2805,
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("Shatter the Sky", "Beat Shatter the Sky", None,
|
||||
lambda state: state._sc2wol_has_competent_comp(world, player)),
|
||||
LocationData("All-In", "All-In: Victory", None)
|
||||
]
|
||||
|
||||
return tuple(location_table)
|
||||
beat_events = []
|
||||
|
||||
for location_data in location_table:
|
||||
if location_data.name.endswith((": Victory", ": Defeat")):
|
||||
beat_events.append(
|
||||
location_data._replace(name="Beat " + location_data.name.rsplit(": ", 1)[0], code=None)
|
||||
)
|
||||
|
||||
return tuple(location_table + beat_events)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from BaseClasses import MultiWorld
|
||||
from ..AutoWorld import LogicMixin
|
||||
from worlds.AutoWorld import LogicMixin
|
||||
|
||||
|
||||
class SC2WoLLogic(LogicMixin):
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from typing import List, Set, Dict, Tuple, Optional, Callable, NamedTuple
|
||||
from typing import List, Set, Dict, Tuple, Optional, Callable
|
||||
from BaseClasses import MultiWorld, Region, Entrance, Location, RegionType
|
||||
from .Locations import LocationData
|
||||
from .Options import get_option_value
|
||||
from worlds.sc2wol.MissionTables import MissionInfo, vanilla_shuffle_order, vanilla_mission_req_table, \
|
||||
from .MissionTables import MissionInfo, vanilla_shuffle_order, vanilla_mission_req_table, \
|
||||
no_build_regions_list, easy_regions_list, medium_regions_list, hard_regions_list
|
||||
import random
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import typing
|
||||
|
||||
from typing import List, Set, Tuple, NamedTuple
|
||||
from typing import List, Set, Tuple
|
||||
from BaseClasses import Item, MultiWorld, Location, Tutorial, ItemClassification
|
||||
from ..AutoWorld import WebWorld
|
||||
from worlds.AutoWorld import WebWorld, World
|
||||
from .Items import StarcraftWoLItem, item_table, filler_items, item_name_groups, get_full_item_list, \
|
||||
basic_unit
|
||||
from .Locations import get_locations
|
||||
from .Regions import create_regions
|
||||
from .Options import sc2wol_options, get_option_value
|
||||
from .LogicMixin import SC2WoLLogic
|
||||
from ..AutoWorld import World
|
||||
|
||||
|
||||
class Starcraft2WoLWebWorld(WebWorld):
|
||||
|
||||
@@ -3,7 +3,8 @@ import os
|
||||
|
||||
import json
|
||||
import Utils
|
||||
from Patch import read_rom, APDeltaPatch
|
||||
from Utils import read_snes_rom
|
||||
from worlds.Files import APDeltaPatch
|
||||
|
||||
SMJUHASH = '21f3e98df4780ee1c667b84e57d88675'
|
||||
ROM_PLAYER_LIMIT = 65535 # max archipelago player ID. note, SM ROM itself will only store 201 names+ids max
|
||||
@@ -22,7 +23,7 @@ def get_base_rom_bytes(file_name: str = "") -> bytes:
|
||||
base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None)
|
||||
if not base_rom_bytes:
|
||||
file_name = get_base_rom_path(file_name)
|
||||
base_rom_bytes = bytes(read_rom(open(file_name, "rb")))
|
||||
base_rom_bytes = bytes(read_snes_rom(open(file_name, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(base_rom_bytes)
|
||||
|
||||
@@ -505,10 +505,8 @@ class SMWorld(World):
|
||||
romPatcher.writeRandoSettings(self.variaRando.randoExec.randoSettings, itemLocs)
|
||||
|
||||
def generate_output(self, output_directory: str):
|
||||
outfilebase = 'AP_' + self.world.seed_name
|
||||
outfilepname = f'_P{self.player}'
|
||||
outfilepname += f"_{self.world.get_file_safe_player_name(self.player).replace(' ', '_')}"
|
||||
outputFilename = os.path.join(output_directory, f'{outfilebase}{outfilepname}.sfc')
|
||||
outfilebase = self.world.get_out_file_name_base(self.player)
|
||||
outputFilename = os.path.join(output_directory, f"{outfilebase}.sfc")
|
||||
|
||||
try:
|
||||
self.variaRando.PatchRom(outputFilename, self.APPrePatchRom, self.APPostPatchRom)
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
- Hardware or software capable of loading and playing SNES ROM files
|
||||
- An emulator capable of connecting to SNI such as:
|
||||
- snes9x Multitroid
|
||||
from: [snes9x Multitroid Download](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz),
|
||||
- snes9x-rr from: [snes9x rr](https://github.com/gocha/snes9x-rr/releases),
|
||||
- BizHawk from: [BizHawk Website](http://tasvideos.org/BizHawk.html)
|
||||
- RetroArch 1.10.1 or newer from: [RetroArch Website](https://retroarch.com?page=platforms). Or,
|
||||
- An SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other
|
||||
@@ -81,7 +80,7 @@ client, and will also create your ROM in the same place as your patch file.
|
||||
When the client launched automatically, SNI should have also automatically launched in the background. If this is its
|
||||
first time launching, you may be prompted to allow it to communicate through the Windows Firewall.
|
||||
|
||||
##### snes9x Multitroid
|
||||
##### snes9x-rr
|
||||
|
||||
1. Load your ROM file if it hasn't already been loaded.
|
||||
2. Click on the File menu and hover on **Lua Scripting**
|
||||
|
||||
@@ -173,7 +173,7 @@ class SM64World(World):
|
||||
}
|
||||
}
|
||||
}
|
||||
filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_file_safe_player_name(self.player)}.apsm64ex"
|
||||
filename = f"{self.world.get_out_file_name_base(self.player)}.apsm64ex"
|
||||
with open(os.path.join(output_directory, filename), 'w') as f:
|
||||
json.dump(data, f)
|
||||
|
||||
|
||||
@@ -52,7 +52,8 @@ Optionally, add `--sm64ap_passwd "YourPassword"` if the room you are using requi
|
||||
The Name in this case is the one specified in your generated .yaml file.
|
||||
In case you are using the Archipelago Website, the IP should be `archipelago.gg`.
|
||||
|
||||
If everything worked out, you will see a textbox informing you the connection has been established after the story intro.
|
||||
Should the connection fail (for example when using the wrong name or IP/Port combination) the game will inform you of that.
|
||||
Additionally, any time the game is not connected (for example when the connection is unstable) it will attempt to reconnect and display a status text.
|
||||
|
||||
# Playing offline
|
||||
|
||||
|
||||
202
worlds/smw/Aesthetics.py
Normal file
202
worlds/smw/Aesthetics.py
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
mario_palettes = [
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x0A, 0x00, 0x1F, 0x39, 0xC4, 0x44, 0x08, 0x4E, 0x70, 0x67, 0xB6, 0x30, 0xDF, 0x35, 0xFF, 0x03], # Mario
|
||||
[0x3F, 0x4F, 0x1D, 0x58, 0x40, 0x11, 0xE0, 0x3F, 0x07, 0x3C, 0xAE, 0x7C, 0xB3, 0x7D, 0x00, 0x2F, 0x5F, 0x16, 0xFF, 0x03], # Luigi
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x0A, 0x00, 0x1F, 0x03, 0xC4, 0x44, 0x08, 0x4E, 0x70, 0x67, 0x16, 0x02, 0xDF, 0x35, 0xFF, 0x03], # Wario
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x0A, 0x00, 0x12, 0x7C, 0xC4, 0x44, 0x08, 0x4E, 0x70, 0x67, 0x0D, 0x58, 0xDF, 0x35, 0xFF, 0x03], # Waluigi
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x0A, 0x00, 0x00, 0x7C, 0xC4, 0x44, 0x08, 0x4E, 0x70, 0x67, 0x00, 0x58, 0xDF, 0x35, 0xFF, 0x03], # Geno
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x0A, 0x00, 0x1F, 0x7C, 0xC4, 0x44, 0x08, 0x4E, 0x70, 0x67, 0x16, 0x58, 0xDF, 0x35, 0xFF, 0x03], # Princess
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x0A, 0x00, 0xE0, 0x00, 0xC4, 0x44, 0x08, 0x4E, 0x70, 0x67, 0x80, 0x00, 0xDF, 0x35, 0xFF, 0x03], # Dark
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x0A, 0x00, 0xFF, 0x01, 0xC4, 0x44, 0x08, 0x4E, 0x70, 0x67, 0x5F, 0x01, 0xDF, 0x35, 0xFF, 0x03], # Sponge
|
||||
]
|
||||
|
||||
fire_mario_palettes = [
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x29, 0x25, 0xFF, 0x7F, 0x08, 0x00, 0x17, 0x00, 0x1F, 0x00, 0x7B, 0x57, 0xDF, 0x0D, 0xFF, 0x03], # Mario
|
||||
[0x1F, 0x3B, 0x1D, 0x58, 0x29, 0x25, 0xFF, 0x7F, 0x40, 0x11, 0xE0, 0x01, 0xE0, 0x02, 0x7B, 0x57, 0xDF, 0x0D, 0xFF, 0x03], # Luigi
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x29, 0x25, 0xFF, 0x7F, 0x08, 0x00, 0x16, 0x02, 0x1F, 0x03, 0x7B, 0x57, 0xDF, 0x0D, 0xFF, 0x03], # Wario
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x29, 0x25, 0xFF, 0x7F, 0x08, 0x00, 0x0D, 0x58, 0x12, 0x7C, 0x7B, 0x57, 0xDF, 0x0D, 0xFF, 0x03], # Waluigi
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x29, 0x25, 0xFF, 0x7F, 0x08, 0x00, 0x00, 0x58, 0x00, 0x7C, 0x7B, 0x57, 0xDF, 0x0D, 0xFF, 0x03], # Geno
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x29, 0x25, 0xFF, 0x7F, 0x08, 0x00, 0x16, 0x58, 0x1F, 0x7C, 0x7B, 0x57, 0xDF, 0x0D, 0xFF, 0x03], # Princess
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x29, 0x25, 0xFF, 0x7F, 0x08, 0x00, 0x80, 0x00, 0xE0, 0x00, 0x7B, 0x57, 0xDF, 0x0D, 0xFF, 0x03], # Dark
|
||||
[0x5F, 0x63, 0x1D, 0x58, 0x29, 0x25, 0xFF, 0x7F, 0x08, 0x00, 0x5F, 0x01, 0xFF, 0x01, 0x7B, 0x57, 0xDF, 0x0D, 0xFF, 0x03], # Sponge
|
||||
]
|
||||
|
||||
ow_mario_palettes = [
|
||||
[0x16, 0x00, 0x1F, 0x00], # Mario
|
||||
[0x80, 0x02, 0xE0, 0x03], # Luigi
|
||||
[0x16, 0x02, 0x1F, 0x03], # Wario
|
||||
[0x0D, 0x58, 0x12, 0x7C], # Waluigi
|
||||
[0x00, 0x58, 0x00, 0x7C], # Geno
|
||||
[0x16, 0x58, 0x1F, 0x7C], # Princess
|
||||
[0x80, 0x00, 0xE0, 0x00], # Dark
|
||||
[0x5F, 0x01, 0xFF, 0x01], # Sponge
|
||||
]
|
||||
|
||||
level_music_address_data = [
|
||||
0x284DB,
|
||||
0x284DC,
|
||||
0x284DD,
|
||||
0x284DE,
|
||||
0x284DF,
|
||||
0x284E0,
|
||||
0x284E1,
|
||||
0x284E2,
|
||||
]
|
||||
|
||||
level_music_value_data = [
|
||||
0x02,
|
||||
0x06,
|
||||
0x01,
|
||||
0x08,
|
||||
0x07,
|
||||
0x03,
|
||||
0x05,
|
||||
0x12,
|
||||
]
|
||||
|
||||
ow_music_address_data = [
|
||||
[0x25BC8, 0x20D8A],
|
||||
[0x25BC9, 0x20D8B],
|
||||
[0x25BCA, 0x20D8C],
|
||||
[0x25BCB, 0x20D8D],
|
||||
[0x25BCC, 0x20D8E],
|
||||
[0x25BCD, 0x20D8F],
|
||||
[0x25BCE, 0x20D90],
|
||||
[0x16C7]
|
||||
]
|
||||
|
||||
ow_music_value_data = [
|
||||
0x02,
|
||||
0x03,
|
||||
0x04,
|
||||
0x06,
|
||||
0x07,
|
||||
0x09,
|
||||
0x05,
|
||||
0x01,
|
||||
]
|
||||
|
||||
valid_foreground_palettes = {
|
||||
0x00: [0x00, 0x01, 0x03, 0x04, 0x05, 0x07], # Normal 1
|
||||
0x01: [0x03, 0x04, 0x05, 0x07], # Castle 1
|
||||
0x02: [0x01, 0x02, 0x03, 0x04, 0x05, 0x07], # Rope 1
|
||||
0x03: [0x02, 0x03, 0x04, 0x05, 0x07], # Underground 1
|
||||
0x04: [0x01, 0x02, 0x03, 0x04, 0x05, 0x07], # Switch Palace 1
|
||||
0x05: [0x04, 0x05], # Ghost House 1
|
||||
0x06: [0x01, 0x02, 0x03, 0x04, 0x05, 0x07], # Rope 2
|
||||
0x07: [0x00, 0x01, 0x03, 0x04, 0x05, 0x07], # Normal 2
|
||||
0x08: [0x01, 0x02, 0x03, 0x04, 0x05, 0x07], # Rope 3
|
||||
0x09: [0x01, 0x02, 0x03, 0x04, 0x05, 0x07], # Underground 2
|
||||
0x0A: [0x01, 0x02, 0x03, 0x04, 0x05, 0x07], # Switch Palace 2
|
||||
0x0B: [0x03, 0x04, 0x05, 0x07], # Castle 2
|
||||
#0x0C: [], # Cloud/Forest
|
||||
0x0D: [0x04, 0x05], # Ghost House 2
|
||||
0x0E: [0x02, 0x03, 0x04, 0x05, 0x07], # Underground 3
|
||||
}
|
||||
|
||||
valid_background_palettes = {
|
||||
0x06861B: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Ghost House Exit
|
||||
0xFFD900: [0x01], # P. Hills
|
||||
0xFFDAB9: [0x04], # Water
|
||||
0xFFDC71: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07], # Hills & Clouds
|
||||
0xFFDD44: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07], # Clouds
|
||||
0xFFDE54: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07], # Small Hills
|
||||
0xFFDF59: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07], # Mountains & Clouds
|
||||
0xFFE103: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07], # Castle Pillars
|
||||
0xFFE472: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07], # Big Hills
|
||||
0xFFE674: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07], # Bonus
|
||||
0xFFE684: [0x01, 0x03, 0x05, 0x06], # Stars
|
||||
0xFFE7C0: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07], # Mountains
|
||||
0xFFE8EE: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Empty/Layer 2
|
||||
0xFFE8FE: [0x01, 0x06], # Cave
|
||||
0xFFEC82: [0x00, 0x02, 0x03, 0x05, 0x06, 0x07], # Bushes
|
||||
0xFFEF80: [0x01, 0x03, 0x05, 0x06], # Ghost House
|
||||
0xFFF175: [0x00, 0x01, 0x02, 0x03, 0x05, 0x06], # Ghost Ship
|
||||
0xFFF45A: [0x01, 0x03, 0x06], # Castle
|
||||
}
|
||||
|
||||
valid_background_colors = {
|
||||
0x06861B: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Ghost House Exit
|
||||
0xFFD900: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # P. Hills
|
||||
0xFFDAB9: [0x02, 0x03, 0x05], # Water
|
||||
0xFFDC71: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Hills & Clouds
|
||||
0xFFDD44: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Clouds
|
||||
0xFFDE54: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Small Hills
|
||||
0xFFDF59: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Mountains & Clouds
|
||||
0xFFE103: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Castle Pillars
|
||||
0xFFE472: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Big Hills
|
||||
0xFFE674: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Bonus
|
||||
0xFFE684: [0x02, 0x03, 0x04, 0x05], # Stars
|
||||
0xFFE7C0: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Mountains
|
||||
0xFFE8EE: [0x03, 0x05], # Empty/Layer 2
|
||||
0xFFE8FE: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Cave
|
||||
0xFFEC82: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Bushes
|
||||
0xFFEF80: [0x03, 0x04], # Ghost House
|
||||
0xFFF175: [0x02, 0x03, 0x04, 0x05], # Ghost Ship
|
||||
0xFFF45A: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Castle
|
||||
}
|
||||
|
||||
def generate_shuffled_level_music(world, player):
|
||||
shuffled_level_music = level_music_value_data.copy()
|
||||
|
||||
if world.music_shuffle[player] == "consistent":
|
||||
world.random.shuffle(shuffled_level_music)
|
||||
elif world.music_shuffle[player] == "singularity":
|
||||
single_song = world.random.choice(shuffled_level_music)
|
||||
shuffled_level_music = [single_song for i in range(len(shuffled_level_music))]
|
||||
|
||||
return shuffled_level_music
|
||||
|
||||
def generate_shuffled_ow_music(world, player):
|
||||
shuffled_ow_music = ow_music_value_data.copy()
|
||||
|
||||
if world.music_shuffle[player] == "consistent" or world.music_shuffle[player] == "full":
|
||||
world.random.shuffle(shuffled_ow_music)
|
||||
elif world.music_shuffle[player] == "singularity":
|
||||
single_song = world.random.choice(shuffled_ow_music)
|
||||
shuffled_ow_music = [single_song for i in range(len(shuffled_ow_music))]
|
||||
|
||||
return shuffled_ow_music
|
||||
|
||||
def generate_shuffled_header_data(rom, world, player):
|
||||
if world.music_shuffle[player] != "full" and not world.foreground_palette_shuffle[player] and not world.background_palette_shuffle[player]:
|
||||
return
|
||||
|
||||
for level_id in range(0, 0x200):
|
||||
layer1_ptr_list = list(rom.read_bytes(0x2E000 + level_id * 3, 3))
|
||||
layer1_ptr = (layer1_ptr_list[2] << 16 | layer1_ptr_list[1] << 8 | layer1_ptr_list[0])
|
||||
|
||||
if layer1_ptr == 0x68000:
|
||||
# Unused Levels
|
||||
continue
|
||||
|
||||
if layer1_ptr >= 0x70000:
|
||||
layer1_ptr -= 0x8000
|
||||
|
||||
layer1_ptr -= 0x38000
|
||||
|
||||
level_header = list(rom.read_bytes(layer1_ptr, 5))
|
||||
|
||||
tileset = level_header[4] & 0x0F
|
||||
|
||||
if world.music_shuffle[player] == "full":
|
||||
level_header[2] &= 0x8F
|
||||
level_header[2] |= (world.random.randint(0, 7) << 5)
|
||||
|
||||
if (world.foreground_palette_shuffle[player] and tileset in valid_foreground_palettes):
|
||||
level_header[3] &= 0xF8
|
||||
level_header[3] |= world.random.choice(valid_foreground_palettes[tileset])
|
||||
|
||||
if world.background_palette_shuffle[player]:
|
||||
layer2_ptr_list = list(rom.read_bytes(0x2E600 + level_id * 3, 3))
|
||||
layer2_ptr = (layer2_ptr_list[2] << 16 | layer2_ptr_list[1] << 8 | layer2_ptr_list[0])
|
||||
|
||||
if layer2_ptr in valid_background_palettes:
|
||||
level_header[0] &= 0x1F
|
||||
level_header[0] |= (world.random.choice(valid_background_palettes[layer2_ptr]) << 5)
|
||||
|
||||
if layer2_ptr in valid_background_colors:
|
||||
level_header[1] &= 0x1F
|
||||
level_header[1] |= (world.random.choice(valid_background_colors[layer2_ptr]) << 5)
|
||||
|
||||
rom.write_bytes(layer1_ptr, bytes(level_header))
|
||||
455
worlds/smw/Client.py
Normal file
455
worlds/smw/Client.py
Normal file
@@ -0,0 +1,455 @@
|
||||
import logging
|
||||
import asyncio
|
||||
import time
|
||||
|
||||
from NetUtils import ClientStatus, color
|
||||
from worlds import AutoWorldRegister
|
||||
from SNIClient import Context, snes_buffered_write, snes_flush_writes, snes_read
|
||||
from .Names.TextBox import generate_received_text
|
||||
from Patch import GAME_SMW
|
||||
|
||||
snes_logger = logging.getLogger("SNES")
|
||||
|
||||
ROM_START = 0x000000
|
||||
WRAM_START = 0xF50000
|
||||
WRAM_SIZE = 0x20000
|
||||
SRAM_START = 0xE00000
|
||||
|
||||
SAVEDATA_START = WRAM_START + 0xF000
|
||||
SAVEDATA_SIZE = 0x500
|
||||
|
||||
SMW_ROMHASH_START = 0x7FC0
|
||||
ROMHASH_SIZE = 0x15
|
||||
|
||||
SMW_PROGRESS_DATA = WRAM_START + 0x1F02
|
||||
SMW_DRAGON_COINS_DATA = WRAM_START + 0x1F2F
|
||||
SMW_PATH_DATA = WRAM_START + 0x1EA2
|
||||
SMW_EVENT_ROM_DATA = ROM_START + 0x2D608
|
||||
SMW_ACTIVE_LEVEL_DATA = ROM_START + 0x37F70
|
||||
|
||||
SMW_GOAL_DATA = ROM_START + 0x01BFA0
|
||||
SMW_REQUIRED_BOSSES_DATA = ROM_START + 0x01BFA1
|
||||
SMW_REQUIRED_EGGS_DATA = ROM_START + 0x01BFA2
|
||||
SMW_SEND_MSG_DATA = ROM_START + 0x01BFA3
|
||||
SMW_RECEIVE_MSG_DATA = ROM_START + 0x01BFA4
|
||||
SMW_DEATH_LINK_ACTIVE_ADDR = ROM_START + 0x01BFA5
|
||||
SMW_DRAGON_COINS_ACTIVE_ADDR = ROM_START + 0x01BFA6
|
||||
SMW_SWAMP_DONUT_GH_ADDR = ROM_START + 0x01BFA7
|
||||
|
||||
SMW_GAME_STATE_ADDR = WRAM_START + 0x100
|
||||
SMW_MARIO_STATE_ADDR = WRAM_START + 0x71
|
||||
SMW_BOSS_STATE_ADDR = WRAM_START + 0xD9B
|
||||
SMW_ACTIVE_BOSS_ADDR = WRAM_START + 0x13FC
|
||||
SMW_CURRENT_LEVEL_ADDR = WRAM_START + 0x13BF
|
||||
SMW_MESSAGE_BOX_ADDR = WRAM_START + 0x1426
|
||||
SMW_BONUS_STAR_ADDR = WRAM_START + 0xF48
|
||||
SMW_EGG_COUNT_ADDR = WRAM_START + 0x1F24
|
||||
SMW_BOSS_COUNT_ADDR = WRAM_START + 0x1F26
|
||||
SMW_NUM_EVENTS_ADDR = WRAM_START + 0x1F2E
|
||||
SMW_SFX_ADDR = WRAM_START + 0x1DFC
|
||||
SMW_PAUSE_ADDR = WRAM_START + 0x13D4
|
||||
SMW_MESSAGE_QUEUE_ADDR = WRAM_START + 0xC391
|
||||
|
||||
SMW_RECV_PROGRESS_ADDR = WRAM_START + 0x1F2B
|
||||
|
||||
SMW_GOAL_LEVELS = [0x28, 0x31, 0x32]
|
||||
SMW_INVALID_MARIO_STATES = [0x05, 0x06, 0x0A, 0x0C, 0x0D]
|
||||
SMW_BAD_TEXT_BOX_LEVELS = [0x26, 0x02, 0x4B]
|
||||
SMW_BOSS_STATES = [0x80, 0xC0, 0xC1]
|
||||
SMW_UNCOLLECTABLE_LEVELS = [0x25, 0x07, 0x0B, 0x40, 0x0E, 0x1F, 0x20, 0x1B, 0x1A, 0x35, 0x34, 0x31, 0x32]
|
||||
|
||||
async def deathlink_kill_player(ctx: Context):
|
||||
if ctx.game == GAME_SMW:
|
||||
game_state = await snes_read(ctx, SMW_GAME_STATE_ADDR, 0x1)
|
||||
if game_state[0] != 0x14:
|
||||
return
|
||||
|
||||
mario_state = await snes_read(ctx, SMW_MARIO_STATE_ADDR, 0x1)
|
||||
if mario_state[0] != 0x00:
|
||||
return
|
||||
|
||||
message_box = await snes_read(ctx, SMW_MESSAGE_BOX_ADDR, 0x1)
|
||||
if message_box[0] != 0x00:
|
||||
return
|
||||
|
||||
pause_state = await snes_read(ctx, SMW_PAUSE_ADDR, 0x1)
|
||||
if pause_state[0] != 0x00:
|
||||
return
|
||||
|
||||
snes_buffered_write(ctx, WRAM_START + 0x9D, bytes([0x30])) # Freeze Gameplay
|
||||
snes_buffered_write(ctx, WRAM_START + 0x1DFB, bytes([0x09])) # Death Music
|
||||
snes_buffered_write(ctx, WRAM_START + 0x0DDA, bytes([0xFF])) # Flush Music Buffer
|
||||
snes_buffered_write(ctx, WRAM_START + 0x1407, bytes([0x00])) # Flush Cape Fly Phase
|
||||
snes_buffered_write(ctx, WRAM_START + 0x140D, bytes([0x00])) # Flush Spin Jump Flag
|
||||
snes_buffered_write(ctx, WRAM_START + 0x188A, bytes([0x00])) # Flush Empty Byte because the game does it
|
||||
snes_buffered_write(ctx, WRAM_START + 0x7D, bytes([0x90])) # Mario Y Speed
|
||||
snes_buffered_write(ctx, WRAM_START + 0x1496, bytes([0x30])) # Death Timer
|
||||
snes_buffered_write(ctx, SMW_MARIO_STATE_ADDR, bytes([0x09])) # Mario State -> Dead
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
from SNIClient import DeathState
|
||||
ctx.death_state = DeathState.dead
|
||||
ctx.last_death_link = time.time()
|
||||
|
||||
return
|
||||
|
||||
|
||||
async def smw_rom_init(ctx: Context):
|
||||
if not ctx.rom:
|
||||
ctx.finished_game = False
|
||||
ctx.death_link_allow_survive = False
|
||||
game_hash = await snes_read(ctx, SMW_ROMHASH_START, ROMHASH_SIZE)
|
||||
if game_hash is None or game_hash == bytes([0] * ROMHASH_SIZE) or game_hash[:3] != b"SMW":
|
||||
return False
|
||||
else:
|
||||
ctx.game = GAME_SMW
|
||||
ctx.items_handling = 0b111 # remote items
|
||||
|
||||
ctx.rom = game_hash
|
||||
|
||||
receive_option = await snes_read(ctx, SMW_RECEIVE_MSG_DATA, 0x1)
|
||||
send_option = await snes_read(ctx, SMW_SEND_MSG_DATA, 0x1)
|
||||
|
||||
ctx.receive_option = receive_option[0]
|
||||
ctx.send_option = send_option[0]
|
||||
|
||||
ctx.message_queue = []
|
||||
|
||||
ctx.allow_collect = True
|
||||
|
||||
death_link = await snes_read(ctx, SMW_DEATH_LINK_ACTIVE_ADDR, 1)
|
||||
if death_link:
|
||||
await ctx.update_death_link(bool(death_link[0] & 0b1))
|
||||
return True
|
||||
|
||||
|
||||
def add_message_to_queue(ctx: Context, new_message):
|
||||
|
||||
if not hasattr(ctx, "message_queue"):
|
||||
ctx.message_queue = []
|
||||
|
||||
ctx.message_queue.append(new_message)
|
||||
|
||||
return
|
||||
|
||||
|
||||
async def handle_message_queue(ctx: Context):
|
||||
|
||||
game_state = await snes_read(ctx, SMW_GAME_STATE_ADDR, 0x1)
|
||||
if game_state[0] != 0x14:
|
||||
return
|
||||
|
||||
mario_state = await snes_read(ctx, SMW_MARIO_STATE_ADDR, 0x1)
|
||||
if mario_state[0] != 0x00:
|
||||
return
|
||||
|
||||
message_box = await snes_read(ctx, SMW_MESSAGE_BOX_ADDR, 0x1)
|
||||
if message_box[0] != 0x00:
|
||||
return
|
||||
|
||||
pause_state = await snes_read(ctx, SMW_PAUSE_ADDR, 0x1)
|
||||
if pause_state[0] != 0x00:
|
||||
return
|
||||
|
||||
current_level = await snes_read(ctx, SMW_CURRENT_LEVEL_ADDR, 0x1)
|
||||
if current_level[0] in SMW_BAD_TEXT_BOX_LEVELS:
|
||||
return
|
||||
|
||||
boss_state = await snes_read(ctx, SMW_BOSS_STATE_ADDR, 0x1)
|
||||
if boss_state[0] in SMW_BOSS_STATES:
|
||||
return
|
||||
|
||||
active_boss = await snes_read(ctx, SMW_ACTIVE_BOSS_ADDR, 0x1)
|
||||
if active_boss[0] != 0x00:
|
||||
return
|
||||
|
||||
if not hasattr(ctx, "message_queue") or len(ctx.message_queue) == 0:
|
||||
return
|
||||
|
||||
next_message = ctx.message_queue.pop(0)
|
||||
|
||||
snes_buffered_write(ctx, SMW_MESSAGE_QUEUE_ADDR, bytes(next_message))
|
||||
snes_buffered_write(ctx, SMW_MESSAGE_BOX_ADDR, bytes([0x03]))
|
||||
snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([0x22]))
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
return
|
||||
|
||||
|
||||
async def smw_game_watcher(ctx: Context):
|
||||
if ctx.game == GAME_SMW:
|
||||
# SMW_TODO: Handle Deathlink
|
||||
game_state = await snes_read(ctx, SMW_GAME_STATE_ADDR, 0x1)
|
||||
mario_state = await snes_read(ctx, SMW_MARIO_STATE_ADDR, 0x1)
|
||||
if game_state is None:
|
||||
# We're not properly connected
|
||||
return
|
||||
elif game_state[0] >= 0x18:
|
||||
if not ctx.finished_game:
|
||||
current_level = await snes_read(ctx, SMW_CURRENT_LEVEL_ADDR, 0x1)
|
||||
|
||||
if current_level[0] in SMW_GOAL_LEVELS:
|
||||
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
|
||||
ctx.finished_game = True
|
||||
return
|
||||
elif game_state[0] < 0x0B:
|
||||
# We haven't loaded a save file
|
||||
ctx.message_queue = []
|
||||
return
|
||||
elif mario_state[0] in SMW_INVALID_MARIO_STATES:
|
||||
# Mario can't come to the phone right now
|
||||
return
|
||||
|
||||
if "DeathLink" in ctx.tags and game_state[0] == 0x14 and ctx.last_death_link + 1 < time.time():
|
||||
currently_dead = mario_state[0] == 0x09
|
||||
await ctx.handle_deathlink_state(currently_dead)
|
||||
|
||||
# Check for Egg Hunt ending
|
||||
goal = await snes_read(ctx, SMW_GOAL_DATA, 0x1)
|
||||
if game_state[0] == 0x14 and goal[0] == 1:
|
||||
current_level = await snes_read(ctx, SMW_CURRENT_LEVEL_ADDR, 0x1)
|
||||
message_box = await snes_read(ctx, SMW_MESSAGE_BOX_ADDR, 0x1)
|
||||
egg_count = await snes_read(ctx, SMW_EGG_COUNT_ADDR, 0x1)
|
||||
required_egg_count = await snes_read(ctx, SMW_REQUIRED_EGGS_DATA, 0x1)
|
||||
|
||||
if current_level[0] == 0x28 and message_box[0] == 0x01 and egg_count[0] >= required_egg_count[0]:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x13C6, bytes([0x08]))
|
||||
snes_buffered_write(ctx, WRAM_START + 0x13CE, bytes([0x01]))
|
||||
snes_buffered_write(ctx, WRAM_START + 0x1DE9, bytes([0x01]))
|
||||
snes_buffered_write(ctx, SMW_GAME_STATE_ADDR, bytes([0x18]))
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
return
|
||||
|
||||
egg_count = await snes_read(ctx, SMW_EGG_COUNT_ADDR, 0x1)
|
||||
boss_count = await snes_read(ctx, SMW_BOSS_COUNT_ADDR, 0x1)
|
||||
display_count = await snes_read(ctx, SMW_BONUS_STAR_ADDR, 0x1)
|
||||
|
||||
if goal[0] == 0 and boss_count[0] > display_count[0]:
|
||||
snes_buffered_write(ctx, SMW_BONUS_STAR_ADDR, bytes([boss_count[0]]))
|
||||
await snes_flush_writes(ctx)
|
||||
elif goal[0] == 1 and egg_count[0] > display_count[0]:
|
||||
snes_buffered_write(ctx, SMW_BONUS_STAR_ADDR, bytes([egg_count[0]]))
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
await handle_message_queue(ctx)
|
||||
|
||||
new_checks = []
|
||||
event_data = await snes_read(ctx, SMW_EVENT_ROM_DATA, 0x60)
|
||||
progress_data = bytearray(await snes_read(ctx, SMW_PROGRESS_DATA, 0x0F))
|
||||
dragon_coins_data = bytearray(await snes_read(ctx, SMW_DRAGON_COINS_DATA, 0x0C))
|
||||
dragon_coins_active = await snes_read(ctx, SMW_DRAGON_COINS_ACTIVE_ADDR, 0x1)
|
||||
from worlds.smw.Rom import item_rom_data, ability_rom_data
|
||||
from worlds.smw.Levels import location_id_to_level_id, level_info_dict
|
||||
for loc_name, level_data in location_id_to_level_id.items():
|
||||
loc_id = AutoWorldRegister.world_types[ctx.game].location_name_to_id[loc_name]
|
||||
if loc_id not in ctx.locations_checked:
|
||||
|
||||
event_id = event_data[level_data[0]]
|
||||
|
||||
if level_data[1] == 2:
|
||||
# Dragon Coins Check
|
||||
if not dragon_coins_active or dragon_coins_active[0] == 0:
|
||||
continue
|
||||
|
||||
progress_byte = (level_data[0] // 8)
|
||||
progress_bit = 7 - (level_data[0] % 8)
|
||||
|
||||
data = dragon_coins_data[progress_byte]
|
||||
masked_data = data & (1 << progress_bit)
|
||||
bit_set = (masked_data != 0)
|
||||
|
||||
if bit_set:
|
||||
# SMW_TODO: Handle non-included checks
|
||||
new_checks.append(loc_id)
|
||||
else:
|
||||
event_id_value = event_id + level_data[1]
|
||||
|
||||
progress_byte = (event_id_value // 8)
|
||||
progress_bit = 7 - (event_id_value % 8)
|
||||
|
||||
data = progress_data[progress_byte]
|
||||
masked_data = data & (1 << progress_bit)
|
||||
bit_set = (masked_data != 0)
|
||||
|
||||
if bit_set:
|
||||
# SMW_TODO: Handle non-included checks
|
||||
new_checks.append(loc_id)
|
||||
|
||||
verify_game_state = await snes_read(ctx, SMW_GAME_STATE_ADDR, 0x1)
|
||||
if verify_game_state is None or verify_game_state[0] < 0x0B or verify_game_state[0] > 0x29:
|
||||
# We have somehow exited the save file (or worse)
|
||||
print("Exit Save File")
|
||||
return
|
||||
|
||||
rom = await snes_read(ctx, SMW_ROMHASH_START, ROMHASH_SIZE)
|
||||
if rom != ctx.rom:
|
||||
ctx.rom = None
|
||||
print("Exit ROM")
|
||||
# We have somehow loaded a different ROM
|
||||
return
|
||||
|
||||
for new_check_id in new_checks:
|
||||
ctx.locations_checked.add(new_check_id)
|
||||
location = ctx.location_names[new_check_id]
|
||||
snes_logger.info(
|
||||
f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})')
|
||||
await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}])
|
||||
|
||||
if game_state[0] != 0x14:
|
||||
# Don't receive items or collect locations outside of in-level mode
|
||||
return
|
||||
|
||||
recv_count = await snes_read(ctx, SMW_RECV_PROGRESS_ADDR, 1)
|
||||
recv_index = recv_count[0]
|
||||
|
||||
if recv_index < len(ctx.items_received):
|
||||
item = ctx.items_received[recv_index]
|
||||
recv_index += 1
|
||||
logging.info('Received %s from %s (%s) (%d/%d in list)' % (
|
||||
color(ctx.item_names[item.item], 'red', 'bold'),
|
||||
color(ctx.player_names[item.player], 'yellow'),
|
||||
ctx.location_names[item.location], recv_index, len(ctx.items_received)))
|
||||
|
||||
if ctx.receive_option == 1 or (ctx.receive_option == 2 and ((item.flags & 1) != 0)):
|
||||
if item.item != 0xBC0012:
|
||||
# Don't send messages for Boss Tokens
|
||||
item_name = ctx.item_names[item.item]
|
||||
player_name = ctx.player_names[item.player]
|
||||
|
||||
receive_message = generate_received_text(item_name, player_name)
|
||||
add_message_to_queue(ctx, receive_message)
|
||||
|
||||
snes_buffered_write(ctx, SMW_RECV_PROGRESS_ADDR, bytes([recv_index]))
|
||||
if item.item in item_rom_data:
|
||||
item_count = await snes_read(ctx, WRAM_START + item_rom_data[item.item][0], 0x1)
|
||||
increment = item_rom_data[item.item][1]
|
||||
|
||||
new_item_count = item_count[0]
|
||||
if increment > 1:
|
||||
new_item_count = increment
|
||||
else:
|
||||
new_item_count += increment
|
||||
|
||||
if verify_game_state[0] == 0x14 and len(item_rom_data[item.item]) > 2:
|
||||
snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([item_rom_data[item.item][2]]))
|
||||
|
||||
snes_buffered_write(ctx, WRAM_START + item_rom_data[item.item][0], bytes([new_item_count]))
|
||||
elif item.item in ability_rom_data:
|
||||
# Handle Upgrades
|
||||
for rom_data in ability_rom_data[item.item]:
|
||||
data = await snes_read(ctx, WRAM_START + rom_data[0], 1)
|
||||
masked_data = data[0] | (1 << rom_data[1])
|
||||
snes_buffered_write(ctx, WRAM_START + rom_data[0], bytes([masked_data]))
|
||||
snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([0x3E])) # SMW_TODO: Custom sounds for each
|
||||
elif item.item == 0xBC000A:
|
||||
# Handle Progressive Powerup
|
||||
data = await snes_read(ctx, WRAM_START + 0x1F2D, 1)
|
||||
mushroom_data = data[0] & (1 << 0)
|
||||
fire_flower_data = data[0] & (1 << 1)
|
||||
cape_data = data[0] & (1 << 2)
|
||||
if mushroom_data == 0:
|
||||
masked_data = data[0] | (1 << 0)
|
||||
snes_buffered_write(ctx, WRAM_START + 0x1F2D, bytes([masked_data]))
|
||||
snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([0x3E]))
|
||||
elif fire_flower_data == 0:
|
||||
masked_data = data[0] | (1 << 1)
|
||||
snes_buffered_write(ctx, WRAM_START + 0x1F2D, bytes([masked_data]))
|
||||
snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([0x3E]))
|
||||
elif cape_data == 0:
|
||||
masked_data = data[0] | (1 << 2)
|
||||
snes_buffered_write(ctx, WRAM_START + 0x1F2D, bytes([masked_data]))
|
||||
snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([0x41]))
|
||||
else:
|
||||
# Extra Powerup?
|
||||
pass
|
||||
elif item.item == 0xBC0015:
|
||||
# Handle Literature Trap
|
||||
from .Names.LiteratureTrap import lit_trap_text_list
|
||||
import random
|
||||
rand_trap = random.choice(lit_trap_text_list)
|
||||
|
||||
for message in rand_trap:
|
||||
add_message_to_queue(ctx, message)
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
# Handle Collected Locations
|
||||
new_events = 0
|
||||
path_data = bytearray(await snes_read(ctx, SMW_PATH_DATA, 0x60))
|
||||
donut_gh_swapped = await snes_read(ctx, SMW_SWAMP_DONUT_GH_ADDR, 0x1)
|
||||
new_dragon_coin = False
|
||||
for loc_id in ctx.checked_locations:
|
||||
if loc_id not in ctx.locations_checked:
|
||||
ctx.locations_checked.add(loc_id)
|
||||
loc_name = ctx.location_names[loc_id]
|
||||
|
||||
if loc_name not in location_id_to_level_id:
|
||||
continue
|
||||
|
||||
level_data = location_id_to_level_id[loc_name]
|
||||
|
||||
if level_data[1] == 2:
|
||||
# Dragon Coins Check
|
||||
|
||||
progress_byte = (level_data[0] // 8)
|
||||
progress_bit = 7 - (level_data[0] % 8)
|
||||
|
||||
data = dragon_coins_data[progress_byte]
|
||||
new_data = data | (1 << progress_bit)
|
||||
dragon_coins_data[progress_byte] = new_data
|
||||
|
||||
new_dragon_coin = True
|
||||
else:
|
||||
if level_data[0] in SMW_UNCOLLECTABLE_LEVELS:
|
||||
continue
|
||||
|
||||
event_id = event_data[level_data[0]]
|
||||
event_id_value = event_id + level_data[1]
|
||||
|
||||
progress_byte = (event_id_value // 8)
|
||||
progress_bit = 7 - (event_id_value % 8)
|
||||
|
||||
data = progress_data[progress_byte]
|
||||
masked_data = data & (1 << progress_bit)
|
||||
bit_set = (masked_data != 0)
|
||||
|
||||
if bit_set:
|
||||
continue
|
||||
|
||||
new_events += 1
|
||||
new_data = data | (1 << progress_bit)
|
||||
progress_data[progress_byte] = new_data
|
||||
|
||||
tile_id = await snes_read(ctx, SMW_ACTIVE_LEVEL_DATA + level_data[0], 0x1)
|
||||
|
||||
level_info = level_info_dict[tile_id[0]]
|
||||
|
||||
path = level_info.exit1Path if level_data[1] == 0 else level_info.exit2Path
|
||||
|
||||
if donut_gh_swapped[0] != 0 and tile_id[0] == 0x04:
|
||||
# Handle Swapped Donut GH Exits
|
||||
path = level_info.exit2Path if level_data[1] == 0 else level_info.exit1Path
|
||||
|
||||
if not path:
|
||||
continue
|
||||
|
||||
this_end_path = path_data[tile_id[0]]
|
||||
new_data = this_end_path | path.thisEndDirection
|
||||
path_data[tile_id[0]] = new_data
|
||||
|
||||
other_end_path = path_data[path.otherLevelID]
|
||||
new_data = other_end_path | path.otherEndDirection
|
||||
path_data[path.otherLevelID] = new_data
|
||||
|
||||
if new_dragon_coin:
|
||||
snes_buffered_write(ctx, SMW_DRAGON_COINS_DATA, bytes(dragon_coins_data))
|
||||
if new_events > 0:
|
||||
snes_buffered_write(ctx, SMW_PROGRESS_DATA, bytes(progress_data))
|
||||
snes_buffered_write(ctx, SMW_PATH_DATA, bytes(path_data))
|
||||
old_events = await snes_read(ctx, SMW_NUM_EVENTS_ADDR, 0x1)
|
||||
snes_buffered_write(ctx, SMW_NUM_EVENTS_ADDR, bytes([old_events[0] + new_events]))
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
69
worlds/smw/Items.py
Normal file
69
worlds/smw/Items.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from .Names import ItemName
|
||||
|
||||
|
||||
class ItemData(typing.NamedTuple):
|
||||
code: typing.Optional[int]
|
||||
progression: bool
|
||||
trap: bool = False
|
||||
quantity: int = 1
|
||||
event: bool = False
|
||||
|
||||
|
||||
class SMWItem(Item):
|
||||
game: str = "Super Mario World"
|
||||
|
||||
|
||||
# Separate tables for each type of item.
|
||||
junk_table = {
|
||||
ItemName.one_up_mushroom: ItemData(0xBC0001, False),
|
||||
}
|
||||
|
||||
collectable_table = {
|
||||
ItemName.yoshi_egg: ItemData(0xBC0002, True),
|
||||
}
|
||||
|
||||
upgrade_table = {
|
||||
ItemName.mario_run: ItemData(0xBC0003, True),
|
||||
ItemName.mario_carry: ItemData(0xBC0004, True),
|
||||
ItemName.mario_swim: ItemData(0xBC0005, True),
|
||||
ItemName.mario_spin_jump: ItemData(0xBC0006, True),
|
||||
ItemName.mario_climb: ItemData(0xBC0007, True),
|
||||
ItemName.yoshi_activate: ItemData(0xBC0008, True),
|
||||
ItemName.p_switch: ItemData(0xBC0009, True),
|
||||
ItemName.progressive_powerup: ItemData(0xBC000A, True),
|
||||
ItemName.p_balloon: ItemData(0xBC000B, True),
|
||||
ItemName.super_star_active: ItemData(0xBC000D, True),
|
||||
}
|
||||
|
||||
switch_palace_table = {
|
||||
ItemName.yellow_switch_palace: ItemData(0xBC000E, True),
|
||||
ItemName.green_switch_palace: ItemData(0xBC000F, True),
|
||||
ItemName.red_switch_palace: ItemData(0xBC0010, True),
|
||||
ItemName.blue_switch_palace: ItemData(0xBC0011, True),
|
||||
}
|
||||
|
||||
trap_table = {
|
||||
ItemName.ice_trap: ItemData(0xBC0013, False, True),
|
||||
ItemName.stun_trap: ItemData(0xBC0014, False, True),
|
||||
ItemName.literature_trap: ItemData(0xBC0015, False, True),
|
||||
}
|
||||
|
||||
event_table = {
|
||||
ItemName.victory: ItemData(0xBC0000, True),
|
||||
ItemName.koopaling: ItemData(0xBC0012, True),
|
||||
}
|
||||
|
||||
# Complete item table.
|
||||
item_table = {
|
||||
**junk_table,
|
||||
**collectable_table,
|
||||
**upgrade_table,
|
||||
**switch_palace_table,
|
||||
**trap_table,
|
||||
**event_table,
|
||||
}
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
||||
579
worlds/smw/Levels.py
Normal file
579
worlds/smw/Levels.py
Normal file
@@ -0,0 +1,579 @@
|
||||
|
||||
from .Names import LocationName
|
||||
|
||||
class SMWPath():
|
||||
thisEndDirection: int
|
||||
otherLevelID: int
|
||||
otherEndDirection: int
|
||||
|
||||
def __init__(self, thisEndDirection: int, otherLevelID: int, otherEndDirection: int):
|
||||
self.thisEndDirection = thisEndDirection
|
||||
self.otherLevelID = otherLevelID
|
||||
self.otherEndDirection = otherEndDirection
|
||||
|
||||
|
||||
class SMWLevel():
|
||||
levelName: str
|
||||
levelIDAddress: int
|
||||
#eventIDAddress: int
|
||||
eventIDValue: int
|
||||
#progressByte: int
|
||||
#progressBit: int
|
||||
exit1Path: SMWPath
|
||||
exit2Path: SMWPath
|
||||
|
||||
def __init__(self, levelName: str, levelIDAddress: int, eventIDValue: int, exit1Path: SMWPath = None, exit2Path: SMWPath = None):
|
||||
self.levelName = levelName
|
||||
self.levelIDAddress = levelIDAddress
|
||||
#self.eventIDAddress = eventIDAddress # Inferred from: LevelIDValue (Dict Key): $2D608 + LevelIDValue
|
||||
self.eventIDValue = eventIDValue
|
||||
#self.progressByte = progressByte # Inferred from EventIDValue: (ID / 8) + $1F02
|
||||
#self.progressBit = progressBit # Inferred from EventIDValue: 1 << (7 - (ID % 8))
|
||||
self.exit1Path = exit1Path
|
||||
self.exit2Path = exit2Path
|
||||
|
||||
|
||||
level_info_dict = {
|
||||
0x28: SMWLevel(LocationName.yoshis_house, 0x37A76, 0x00),
|
||||
0x29: SMWLevel(LocationName.yoshis_island_1_region, 0x37A83, 0x01, SMWPath(0x08, 0x14, 0x04)),
|
||||
0x14: SMWLevel(LocationName.yellow_switch_palace, 0x37812, 0x02),
|
||||
0x2A: SMWLevel(LocationName.yoshis_island_2_region, 0x37A89, 0x03, SMWPath(0x08, 0x27, 0x04)),
|
||||
0x27: SMWLevel(LocationName.yoshis_island_3_region, 0x37A69, 0x04, SMWPath(0x01, 0x26, 0x04)),
|
||||
0x26: SMWLevel(LocationName.yoshis_island_4_region, 0x37A4B, 0x05, SMWPath(0x08, 0x25, 0x01)),
|
||||
0x25: SMWLevel(LocationName.yoshis_island_castle_region, 0x37A29, 0x06, SMWPath(0x08, 0x15, 0x04)),
|
||||
|
||||
0x15: SMWLevel(LocationName.donut_plains_1_region, 0x37815, 0x07, SMWPath(0x02, 0x09, 0x04), SMWPath(0x08, 0x0A, 0x04)),
|
||||
0x09: SMWLevel(LocationName.donut_plains_2_region, 0x376D3, 0x09, SMWPath(0x08, 0x04, 0x02), SMWPath(0x02, 0x08, 0x01)),
|
||||
0x0A: SMWLevel(LocationName.donut_secret_1_region, 0x376E5, 0x10, SMWPath(0x08, 0x04, 0x04), SMWPath(0x01, 0x13, 0x08)),
|
||||
0x08: SMWLevel(LocationName.green_switch_palace, 0x376D1, 0x28),
|
||||
0x04: SMWLevel(LocationName.donut_ghost_house_region, 0x376A5, 0x0B, SMWPath(0x08, 0x03, 0x04), SMWPath(0x01, 0x05, 0x02)),
|
||||
0x13: SMWLevel(LocationName.donut_secret_house_region, 0x37807, 0x12, SMWPath(0x01, 0x2F, 0x04), SMWPath(0x04, 0x16, 0x08)), # SMW_TODO: Check this wrt pipe behavior
|
||||
0x05: SMWLevel(LocationName.donut_plains_3_region, 0x376A9, 0x0D, SMWPath(0x01, 0x06, 0x08)),
|
||||
0x06: SMWLevel(LocationName.donut_plains_4_region, 0x376CB, 0x0E, SMWPath(0x01, 0x07, 0x02)),
|
||||
0x2F: SMWLevel(LocationName.donut_secret_2_region, 0x37B10, 0x14, SMWPath(0x01, 0x05, 0x04)),
|
||||
0x07: SMWLevel(LocationName.donut_plains_castle_region, 0x376CD, 0x0F, SMWPath(0x08, 0x3E, 0x04)),
|
||||
0x03: SMWLevel(LocationName.donut_plains_top_secret, 0x37685, 0xFF),
|
||||
0x16: SMWLevel(LocationName.donut_plains_star_road, 0x37827, 0xFF),
|
||||
|
||||
0x3E: SMWLevel(LocationName.vanilla_dome_1_region, 0x37C25, 0x15, SMWPath(0x01, 0x3C, 0x04), SMWPath(0x02, 0x2D, 0x04)),
|
||||
0x3C: SMWLevel(LocationName.vanilla_dome_2_region, 0x37C08, 0x17, SMWPath(0x08, 0x2B, 0x04), SMWPath(0x01, 0x3F, 0x08)),
|
||||
0x2D: SMWLevel(LocationName.vanilla_secret_1_region, 0x37AE3, 0x1D, SMWPath(0x08, 0x01, 0x02), SMWPath(0x02, 0x2C, 0x01)),
|
||||
0x2B: SMWLevel(LocationName.vanilla_ghost_house_region, 0x37AC8, 0x19, SMWPath(0x01, 0x2E, 0x08)),
|
||||
0x2E: SMWLevel(LocationName.vanilla_dome_3_region, 0x37AEC, 0x1A, SMWPath(0x04, 0x3D, 0x08)),
|
||||
0x3D: SMWLevel(LocationName.vanilla_dome_4_region, 0x37C0C, 0x1B, SMWPath(0x04, 0x40, 0x08)),
|
||||
0x3F: SMWLevel(LocationName.red_switch_palace, 0x37C2A, 0x29),
|
||||
0x01: SMWLevel(LocationName.vanilla_secret_2_region, 0x3763C, 0x1F, SMWPath(0x01, 0x02, 0x02)),
|
||||
0x02: SMWLevel(LocationName.vanilla_secret_3_region, 0x3763E, 0x20, SMWPath(0x01, 0x0B, 0x02)),
|
||||
0x0B: SMWLevel(LocationName.vanilla_fortress_region, 0x37730, 0x21, SMWPath(0x01, 0x0C, 0x02)),
|
||||
0x40: SMWLevel(LocationName.vanilla_dome_castle_region, 0x37C2C, 0x1C, SMWPath(0x04, 0x0F, 0x02)),
|
||||
0x2C: SMWLevel(LocationName.vanilla_dome_star_road, 0x37AE0, 0xFF),
|
||||
|
||||
0x0C: SMWLevel(LocationName.butter_bridge_1_region, 0x37734, 0x22, SMWPath(0x01, 0x0D, 0x02)),
|
||||
0x0D: SMWLevel(LocationName.butter_bridge_2_region, 0x37736, 0x23, SMWPath(0x01, 0x0E, 0x02)),
|
||||
0x0F: SMWLevel(LocationName.cheese_bridge_region, 0x37754, 0x25, SMWPath(0x01, 0x10, 0x02), SMWPath(0x04, 0x11, 0x08)),
|
||||
0x11: SMWLevel(LocationName.soda_lake_region, 0x37784, 0x60, SMWPath(0x04, 0x12, 0x04)),
|
||||
0x10: SMWLevel(LocationName.cookie_mountain_region, 0x37757, 0x27, SMWPath(0x04, 0x0E, 0x04)),
|
||||
0x0E: SMWLevel(LocationName.twin_bridges_castle_region, 0x3773A, 0x24, SMWPath(0x01, 0x42, 0x08)),
|
||||
0x12: SMWLevel(LocationName.twin_bridges_star_road, 0x377F0, 0xFF),
|
||||
|
||||
0x42: SMWLevel(LocationName.forest_of_illusion_1_region, 0x37C78, 0x2A, SMWPath(0x01, 0x44, 0x08), SMWPath(0x02, 0x41, 0x01)),
|
||||
0x44: SMWLevel(LocationName.forest_of_illusion_2_region, 0x37CAA, 0x2C, SMWPath(0x04, 0x47, 0x08), SMWPath(0x01, 0x45, 0x02)),
|
||||
0x47: SMWLevel(LocationName.forest_of_illusion_3_region, 0x37CC8, 0x2E, SMWPath(0x02, 0x41, 0x04), SMWPath(0x04, 0x20, 0x01)),
|
||||
0x43: SMWLevel(LocationName.forest_of_illusion_4_region, 0x37CA4, 0x32, SMWPath(0x01, 0x44, 0x02), SMWPath(0x04, 0x46, 0x08)),
|
||||
0x41: SMWLevel(LocationName.forest_ghost_house_region, 0x37C76, 0x30, SMWPath(0x01, 0x42, 0x02), SMWPath(0x02, 0x43, 0x08)),
|
||||
0x46: SMWLevel(LocationName.forest_secret_region, 0x37CC4, 0x34, SMWPath(0x04, 0x1F, 0x01)),
|
||||
0x45: SMWLevel(LocationName.blue_switch_palace, 0x37CAC, 0x37),
|
||||
0x1F: SMWLevel(LocationName.forest_fortress_region, 0x37906, 0x35, SMWPath(0x02, 0x1E, 0x01)),
|
||||
0x20: SMWLevel(LocationName.forest_castle_region, 0x37928, 0x61, SMWPath(0x04, 0x22, 0x08)),
|
||||
0x1E: SMWLevel(LocationName.forest_star_road, 0x37904, 0x36),
|
||||
|
||||
0x22: SMWLevel(LocationName.chocolate_island_1_region, 0x37968, 0x62, SMWPath(0x02, 0x21, 0x01)),
|
||||
0x24: SMWLevel(LocationName.chocolate_island_2_region, 0x379B5, 0x46, SMWPath(0x02, 0x23, 0x01), SMWPath(0x04, 0x3B, 0x01)),
|
||||
0x23: SMWLevel(LocationName.chocolate_island_3_region, 0x379B3, 0x48, SMWPath(0x04, 0x23, 0x08), SMWPath(0x02, 0x1B, 0x01)),
|
||||
0x1D: SMWLevel(LocationName.chocolate_island_4_region, 0x378DF, 0x4B, SMWPath(0x02, 0x1C, 0x01)),
|
||||
0x1C: SMWLevel(LocationName.chocolate_island_5_region, 0x378DC, 0x4C, SMWPath(0x08, 0x1A, 0x04)),
|
||||
0x21: SMWLevel(LocationName.chocolate_ghost_house_region, 0x37965, 0x63, SMWPath(0x04, 0x24, 0x08)),
|
||||
0x1B: SMWLevel(LocationName.chocolate_fortress_region, 0x378BF, 0x4A, SMWPath(0x04, 0x1D, 0x08)),
|
||||
0x3B: SMWLevel(LocationName.chocolate_secret_region, 0x37B97, 0x4F, SMWPath(0x02, 0x1A, 0x02)),
|
||||
0x1A: SMWLevel(LocationName.chocolate_castle_region, 0x378BC, 0x4D, SMWPath(0x08, 0x18, 0x02)),
|
||||
|
||||
0x18: SMWLevel(LocationName.sunken_ghost_ship_region, 0x3787E, 0x4E, SMWPath(0x08, 0x3A, 0x01)),
|
||||
0x3A: SMWLevel(LocationName.valley_of_bowser_1_region, 0x37B7B, 0x38, SMWPath(0x02, 0x39, 0x01)),
|
||||
0x39: SMWLevel(LocationName.valley_of_bowser_2_region, 0x37B79, 0x39, SMWPath(0x02, 0x38, 0x01), SMWPath(0x08, 0x35, 0x04)),
|
||||
0x37: SMWLevel(LocationName.valley_of_bowser_3_region, 0x37B74, 0x3D, SMWPath(0x08, 0x33, 0x04)),
|
||||
0x33: SMWLevel(LocationName.valley_of_bowser_4_region, 0x37B54, 0x3E, SMWPath(0x01, 0x34, 0x02), SMWPath(0x08, 0x30, 0x04)),
|
||||
0x38: SMWLevel(LocationName.valley_ghost_house_region, 0x37B77, 0x3B, SMWPath(0x02, 0x37, 0x01), SMWPath(0x08, 0x34, 0x04)),
|
||||
0x35: SMWLevel(LocationName.valley_fortress_region, 0x37B59, 0x41, SMWPath(0x08, 0x32, 0x04)),
|
||||
0x34: SMWLevel(LocationName.valley_castle_region, 0x37B57, 0x40, SMWPath(0x08, 0x31, 0x04)),
|
||||
0x31: SMWLevel(LocationName.front_door, 0x37B37, 0x45),
|
||||
0x81: SMWLevel(LocationName.front_door, 0x37B37, 0x45), # Fake Extra Front Door
|
||||
0x32: SMWLevel(LocationName.back_door, 0x37B39, 0x42),
|
||||
0x82: SMWLevel(LocationName.back_door, 0x37B39, 0x42), # Fake Extra Back Door
|
||||
0x30: SMWLevel(LocationName.valley_star_road, 0x37B34, 0x44),
|
||||
|
||||
0x5B: SMWLevel(LocationName.star_road_donut, 0x37DD3, 0x50),
|
||||
0x58: SMWLevel(LocationName.star_road_1_region, 0x37DA4, 0x51, None, SMWPath(0x02, 0x53, 0x04)),
|
||||
0x53: SMWLevel(LocationName.star_road_vanilla, 0x37D82, 0x53),
|
||||
0x54: SMWLevel(LocationName.star_road_2_region, 0x37D85, 0x54, None, SMWPath(0x08, 0x52, 0x02)),
|
||||
0x52: SMWLevel(LocationName.star_road_twin_bridges, 0x37D67, 0x56),
|
||||
0x56: SMWLevel(LocationName.star_road_3_region, 0x37D89, 0x57, None, SMWPath(0x01, 0x57, 0x02)),
|
||||
0x57: SMWLevel(LocationName.star_road_forest, 0x37D8C, 0x59),
|
||||
0x59: SMWLevel(LocationName.star_road_4_region, 0x37DAA, 0x5A, None, SMWPath(0x04, 0x5C, 0x08)),
|
||||
0x5C: SMWLevel(LocationName.star_road_valley, 0x37DDC, 0x5C),
|
||||
0x5A: SMWLevel(LocationName.star_road_5_region, 0x37DB7, 0x5D, SMWPath(0x02, 0x5B, 0x01), SMWPath(0x08, 0x55, 0x04)),
|
||||
0x55: SMWLevel(LocationName.star_road_special, 0x37D87, 0x5F),
|
||||
|
||||
0x4D: SMWLevel(LocationName.special_star_road, 0x37D31, 0x64),
|
||||
0x4E: SMWLevel(LocationName.special_zone_1_region, 0x37D33, 0x65, SMWPath(0x01, 0x4F, 0x02)),
|
||||
0x4F: SMWLevel(LocationName.special_zone_2_region, 0x37D36, 0x66, SMWPath(0x01, 0x50, 0x02)),
|
||||
0x50: SMWLevel(LocationName.special_zone_3_region, 0x37D39, 0x67, SMWPath(0x01, 0x51, 0x02)),
|
||||
0x51: SMWLevel(LocationName.special_zone_4_region, 0x37D3C, 0x68, SMWPath(0x01, 0x4C, 0x01)),
|
||||
0x4C: SMWLevel(LocationName.special_zone_5_region, 0x37D1C, 0x69, SMWPath(0x02, 0x4B, 0x01)),
|
||||
0x4B: SMWLevel(LocationName.special_zone_6_region, 0x37D19, 0x6A, SMWPath(0x02, 0x4A, 0x01)),
|
||||
0x4A: SMWLevel(LocationName.special_zone_7_region, 0x37D16, 0x6B, SMWPath(0x02, 0x49, 0x01)),
|
||||
0x49: SMWLevel(LocationName.special_zone_8_region, 0x37D13, 0x6C, SMWPath(0x02, 0x48, 0x01)),
|
||||
0x48: SMWLevel(LocationName.special_complete, 0x37D11, 0x6D),
|
||||
}
|
||||
|
||||
full_level_list = [
|
||||
0x28, 0x29, 0x14, 0x2A, 0x27, 0x26, 0x25,
|
||||
0x15, 0x09, 0x0A, 0x08, 0x04, 0x13, 0x05, 0x06, 0x2F, 0x07, 0x03, 0x16,
|
||||
0x3E, 0x3C, 0x2D, 0x2B, 0x2E, 0x3D, 0x3F, 0x01, 0x02, 0x0B, 0x40, 0x2C,
|
||||
0x0C, 0x0D, 0x0F, 0x11, 0x10, 0x0E, 0x12,
|
||||
0x42, 0x44, 0x47, 0x43, 0x41, 0x46, 0x45, 0x1F, 0x20, 0x1E,
|
||||
0x22, 0x24, 0x23, 0x1D, 0x1C, 0x21, 0x1B, 0x3B, 0x1A,
|
||||
0x18, 0x3A, 0x39, 0x37, 0x33, 0x38, 0x35, 0x34, 0x31, 0x32, 0x30,
|
||||
0x5B, 0x58, 0x53, 0x54, 0x52, 0x56, 0x57, 0x59, 0x5C, 0x5A, 0x55,
|
||||
0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
|
||||
]
|
||||
|
||||
submap_level_list = [
|
||||
0x28, 0x29, 0x2A, 0x27, 0x26, 0x25,
|
||||
0x2F,
|
||||
0x3E, 0x3C, 0x2D, 0x2B, 0x2E, 0x3D, 0x3F, 0x40, 0x2C,
|
||||
0x42, 0x44, 0x47, 0x43, 0x41, 0x46, 0x45,
|
||||
0x3B,
|
||||
0x3A, 0x39, 0x37, 0x33, 0x38, 0x35, 0x34, 0x31, 0x32, 0x30,
|
||||
0x5B, 0x58, 0x53, 0x54, 0x52, 0x56, 0x57, 0x59, 0x5C, 0x5A, 0x55,
|
||||
0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
|
||||
]
|
||||
|
||||
easy_castle_fortress_levels = [
|
||||
0x07,
|
||||
0x40,
|
||||
0x1F,
|
||||
0x20,
|
||||
0x1B,
|
||||
0x34,
|
||||
]
|
||||
|
||||
hard_castle_fortress_levels = [
|
||||
0x25,
|
||||
0x0B,
|
||||
0x0E,
|
||||
0x1A,
|
||||
0x35,
|
||||
]
|
||||
|
||||
easy_single_levels = [
|
||||
0x29,
|
||||
0x2A,
|
||||
0x27,
|
||||
0x26,
|
||||
0x05,
|
||||
0x06,
|
||||
0x2F,
|
||||
0x2E,
|
||||
0x3D,
|
||||
0x01,
|
||||
0x0C,
|
||||
0x0D,
|
||||
0x46,
|
||||
0x1D,
|
||||
]
|
||||
|
||||
hard_single_levels = [
|
||||
0x2B,
|
||||
0x02,
|
||||
0x11,
|
||||
0x10,
|
||||
0x22,
|
||||
0x1C,
|
||||
0x21,
|
||||
0x3B,
|
||||
0x3A,
|
||||
0x37,
|
||||
0x4E,
|
||||
0x4F,
|
||||
0x50,
|
||||
0x51,
|
||||
0x4C,
|
||||
0x4B,
|
||||
0x4A,
|
||||
0x49,
|
||||
]
|
||||
|
||||
easy_double_levels = [
|
||||
0x15,
|
||||
0x09,
|
||||
0x0F,
|
||||
0x42,
|
||||
0x43,
|
||||
0x24,
|
||||
0x38,
|
||||
0x58,
|
||||
0x54,
|
||||
0x56,
|
||||
]
|
||||
|
||||
hard_double_levels = [
|
||||
0x0A,
|
||||
0x04,
|
||||
0x13,
|
||||
0x3E,
|
||||
0x3C,
|
||||
0x2D,
|
||||
0x44,
|
||||
0x47,
|
||||
0x41,
|
||||
0x23,
|
||||
0x33,
|
||||
0x39,
|
||||
0x59,
|
||||
0x5A,
|
||||
]
|
||||
|
||||
switch_palace_levels = [
|
||||
0x14,
|
||||
0x08,
|
||||
0x3F,
|
||||
0x45,
|
||||
]
|
||||
|
||||
location_id_to_level_id = {
|
||||
LocationName.yoshis_island_1_exit_1: [0x29, 0],
|
||||
LocationName.yoshis_island_1_dragon: [0x29, 2],
|
||||
LocationName.yoshis_island_2_exit_1: [0x2A, 0],
|
||||
LocationName.yoshis_island_2_dragon: [0x2A, 2],
|
||||
LocationName.yoshis_island_3_exit_1: [0x27, 0],
|
||||
LocationName.yoshis_island_3_dragon: [0x27, 2],
|
||||
LocationName.yoshis_island_4_exit_1: [0x26, 0],
|
||||
LocationName.yoshis_island_4_dragon: [0x26, 2],
|
||||
LocationName.yoshis_island_castle: [0x25, 0],
|
||||
LocationName.yoshis_island_koopaling: [0x25, 0],
|
||||
LocationName.yellow_switch_palace: [0x14, 0],
|
||||
|
||||
LocationName.donut_plains_1_exit_1: [0x15, 0],
|
||||
LocationName.donut_plains_1_exit_2: [0x15, 1],
|
||||
LocationName.donut_plains_1_dragon: [0x15, 2],
|
||||
LocationName.donut_plains_2_exit_1: [0x09, 0],
|
||||
LocationName.donut_plains_2_exit_2: [0x09, 1],
|
||||
LocationName.donut_plains_2_dragon: [0x09, 2],
|
||||
LocationName.donut_plains_3_exit_1: [0x05, 0],
|
||||
LocationName.donut_plains_3_dragon: [0x05, 2],
|
||||
LocationName.donut_plains_4_exit_1: [0x06, 0],
|
||||
LocationName.donut_plains_4_dragon: [0x06, 2],
|
||||
LocationName.donut_secret_1_exit_1: [0x0A, 0],
|
||||
LocationName.donut_secret_1_exit_2: [0x0A, 1],
|
||||
LocationName.donut_secret_1_dragon: [0x0A, 2],
|
||||
LocationName.donut_secret_2_exit_1: [0x2F, 0],
|
||||
LocationName.donut_secret_2_dragon: [0x2F, 2],
|
||||
LocationName.donut_ghost_house_exit_1: [0x04, 0],
|
||||
LocationName.donut_ghost_house_exit_2: [0x04, 1],
|
||||
LocationName.donut_secret_house_exit_1: [0x13, 0],
|
||||
LocationName.donut_secret_house_exit_2: [0x13, 1],
|
||||
LocationName.donut_plains_castle: [0x07, 0],
|
||||
LocationName.donut_plains_koopaling: [0x07, 0],
|
||||
LocationName.green_switch_palace: [0x08, 0],
|
||||
|
||||
LocationName.vanilla_dome_1_exit_1: [0x3E, 0],
|
||||
LocationName.vanilla_dome_1_exit_2: [0x3E, 1],
|
||||
LocationName.vanilla_dome_1_dragon: [0x3E, 2],
|
||||
LocationName.vanilla_dome_2_exit_1: [0x3C, 0],
|
||||
LocationName.vanilla_dome_2_exit_2: [0x3C, 1],
|
||||
LocationName.vanilla_dome_2_dragon: [0x3C, 2],
|
||||
LocationName.vanilla_dome_3_exit_1: [0x2E, 0],
|
||||
LocationName.vanilla_dome_3_dragon: [0x2E, 2],
|
||||
LocationName.vanilla_dome_4_exit_1: [0x3D, 0],
|
||||
LocationName.vanilla_dome_4_dragon: [0x3D, 2],
|
||||
LocationName.vanilla_secret_1_exit_1: [0x2D, 0],
|
||||
LocationName.vanilla_secret_1_exit_2: [0x2D, 1],
|
||||
LocationName.vanilla_secret_1_dragon: [0x2D, 2],
|
||||
LocationName.vanilla_secret_2_exit_1: [0x01, 0],
|
||||
LocationName.vanilla_secret_2_dragon: [0x01, 2],
|
||||
LocationName.vanilla_secret_3_exit_1: [0x02, 0],
|
||||
LocationName.vanilla_secret_3_dragon: [0x02, 2],
|
||||
LocationName.vanilla_ghost_house_exit_1: [0x2B, 0],
|
||||
LocationName.vanilla_ghost_house_dragon: [0x2B, 2],
|
||||
LocationName.vanilla_fortress: [0x0B, 0],
|
||||
LocationName.vanilla_reznor: [0x0B, 0],
|
||||
LocationName.vanilla_dome_castle: [0x40, 0],
|
||||
LocationName.vanilla_dome_koopaling: [0x40, 0],
|
||||
LocationName.red_switch_palace: [0x3F, 0],
|
||||
|
||||
LocationName.butter_bridge_1_exit_1: [0x0C, 0],
|
||||
LocationName.butter_bridge_1_dragon: [0x0C, 2],
|
||||
LocationName.butter_bridge_2_exit_1: [0x0D, 0],
|
||||
LocationName.butter_bridge_2_dragon: [0x0D, 2],
|
||||
LocationName.cheese_bridge_exit_1: [0x0F, 0],
|
||||
LocationName.cheese_bridge_exit_2: [0x0F, 1],
|
||||
LocationName.cheese_bridge_dragon: [0x0F, 2],
|
||||
LocationName.cookie_mountain_exit_1: [0x10, 0],
|
||||
LocationName.cookie_mountain_dragon: [0x10, 2],
|
||||
LocationName.soda_lake_exit_1: [0x11, 0],
|
||||
LocationName.soda_lake_dragon: [0x11, 2],
|
||||
LocationName.twin_bridges_castle: [0x0E, 0],
|
||||
LocationName.twin_bridges_koopaling: [0x0E, 0],
|
||||
|
||||
LocationName.forest_of_illusion_1_exit_1: [0x42, 0],
|
||||
LocationName.forest_of_illusion_1_exit_2: [0x42, 1],
|
||||
LocationName.forest_of_illusion_2_exit_1: [0x44, 0],
|
||||
LocationName.forest_of_illusion_2_exit_2: [0x44, 1],
|
||||
LocationName.forest_of_illusion_2_dragon: [0x44, 2],
|
||||
LocationName.forest_of_illusion_3_exit_1: [0x47, 0],
|
||||
LocationName.forest_of_illusion_3_exit_2: [0x47, 1],
|
||||
LocationName.forest_of_illusion_3_dragon: [0x47, 2],
|
||||
LocationName.forest_of_illusion_4_exit_1: [0x43, 0],
|
||||
LocationName.forest_of_illusion_4_exit_2: [0x43, 1],
|
||||
LocationName.forest_of_illusion_4_dragon: [0x43, 2],
|
||||
LocationName.forest_ghost_house_exit_1: [0x41, 0],
|
||||
LocationName.forest_ghost_house_exit_2: [0x41, 1],
|
||||
LocationName.forest_ghost_house_dragon: [0x41, 2],
|
||||
LocationName.forest_secret_exit_1: [0x46, 0],
|
||||
LocationName.forest_secret_dragon: [0x46, 2],
|
||||
LocationName.forest_fortress: [0x1F, 0],
|
||||
LocationName.forest_reznor: [0x1F, 0],
|
||||
LocationName.forest_castle: [0x20, 0],
|
||||
LocationName.forest_koopaling: [0x20, 0],
|
||||
LocationName.forest_castle_dragon: [0x20, 2],
|
||||
LocationName.blue_switch_palace: [0x45, 0],
|
||||
|
||||
LocationName.chocolate_island_1_exit_1: [0x22, 0],
|
||||
LocationName.chocolate_island_1_dragon: [0x22, 2],
|
||||
LocationName.chocolate_island_2_exit_1: [0x24, 0],
|
||||
LocationName.chocolate_island_2_exit_2: [0x24, 1],
|
||||
LocationName.chocolate_island_2_dragon: [0x24, 2],
|
||||
LocationName.chocolate_island_3_exit_1: [0x23, 0],
|
||||
LocationName.chocolate_island_3_exit_2: [0x23, 1],
|
||||
LocationName.chocolate_island_3_dragon: [0x23, 2],
|
||||
LocationName.chocolate_island_4_exit_1: [0x1D, 0],
|
||||
LocationName.chocolate_island_4_dragon: [0x1D, 2],
|
||||
LocationName.chocolate_island_5_exit_1: [0x1C, 0],
|
||||
LocationName.chocolate_island_5_dragon: [0x1C, 2],
|
||||
LocationName.chocolate_ghost_house_exit_1: [0x21, 0],
|
||||
LocationName.chocolate_secret_exit_1: [0x3B, 0],
|
||||
LocationName.chocolate_fortress: [0x1B, 0],
|
||||
LocationName.chocolate_reznor: [0x1B, 0],
|
||||
LocationName.chocolate_castle: [0x1A, 0],
|
||||
LocationName.chocolate_koopaling: [0x1A, 0],
|
||||
|
||||
LocationName.sunken_ghost_ship: [0x18, 0],
|
||||
LocationName.sunken_ghost_ship_dragon: [0x18, 2],
|
||||
|
||||
LocationName.valley_of_bowser_1_exit_1: [0x3A, 0],
|
||||
LocationName.valley_of_bowser_1_dragon: [0x3A, 2],
|
||||
LocationName.valley_of_bowser_2_exit_1: [0x39, 0],
|
||||
LocationName.valley_of_bowser_2_exit_2: [0x39, 1],
|
||||
LocationName.valley_of_bowser_2_dragon: [0x39, 2],
|
||||
LocationName.valley_of_bowser_3_exit_1: [0x37, 0],
|
||||
LocationName.valley_of_bowser_3_dragon: [0x37, 2],
|
||||
LocationName.valley_of_bowser_4_exit_1: [0x33, 0],
|
||||
LocationName.valley_of_bowser_4_exit_2: [0x33, 1],
|
||||
LocationName.valley_ghost_house_exit_1: [0x38, 0],
|
||||
LocationName.valley_ghost_house_exit_2: [0x38, 1],
|
||||
LocationName.valley_ghost_house_dragon: [0x38, 2],
|
||||
LocationName.valley_fortress: [0x35, 0],
|
||||
LocationName.valley_reznor: [0x35, 0],
|
||||
LocationName.valley_castle: [0x34, 0],
|
||||
LocationName.valley_koopaling: [0x34, 0],
|
||||
LocationName.valley_castle_dragon: [0x34, 2],
|
||||
|
||||
LocationName.star_road_1_exit_1: [0x58, 0],
|
||||
LocationName.star_road_1_exit_2: [0x58, 1],
|
||||
LocationName.star_road_1_dragon: [0x58, 2],
|
||||
LocationName.star_road_2_exit_1: [0x54, 0],
|
||||
LocationName.star_road_2_exit_2: [0x54, 1],
|
||||
LocationName.star_road_3_exit_1: [0x56, 0],
|
||||
LocationName.star_road_3_exit_2: [0x56, 1],
|
||||
LocationName.star_road_4_exit_1: [0x59, 0],
|
||||
LocationName.star_road_4_exit_2: [0x59, 1],
|
||||
LocationName.star_road_5_exit_1: [0x5A, 0],
|
||||
LocationName.star_road_5_exit_2: [0x5A, 1],
|
||||
|
||||
LocationName.special_zone_1_exit_1: [0x4E, 0],
|
||||
LocationName.special_zone_1_dragon: [0x4E, 2],
|
||||
LocationName.special_zone_2_exit_1: [0x4F, 0],
|
||||
LocationName.special_zone_2_dragon: [0x4F, 2],
|
||||
LocationName.special_zone_3_exit_1: [0x50, 0],
|
||||
LocationName.special_zone_3_dragon: [0x50, 2],
|
||||
LocationName.special_zone_4_exit_1: [0x51, 0],
|
||||
LocationName.special_zone_4_dragon: [0x51, 2],
|
||||
LocationName.special_zone_5_exit_1: [0x4C, 0],
|
||||
LocationName.special_zone_5_dragon: [0x4C, 2],
|
||||
LocationName.special_zone_6_exit_1: [0x4B, 0],
|
||||
LocationName.special_zone_6_dragon: [0x4B, 2],
|
||||
LocationName.special_zone_7_exit_1: [0x4A, 0],
|
||||
LocationName.special_zone_7_dragon: [0x4A, 2],
|
||||
LocationName.special_zone_8_exit_1: [0x49, 0],
|
||||
LocationName.special_zone_8_dragon: [0x49, 2],
|
||||
}
|
||||
|
||||
def generate_level_list(world, player):
|
||||
|
||||
if not world.level_shuffle[player]:
|
||||
out_level_list = full_level_list.copy()
|
||||
out_level_list[0x00] = 0x03
|
||||
out_level_list[0x11] = 0x28
|
||||
|
||||
if world.bowser_castle_doors[player] == "fast":
|
||||
out_level_list[0x41] = 0x82
|
||||
out_level_list[0x42] = 0x32
|
||||
elif world.bowser_castle_doors[player] == "slow":
|
||||
out_level_list[0x41] = 0x31
|
||||
out_level_list[0x42] = 0x81
|
||||
|
||||
return out_level_list
|
||||
|
||||
shuffled_level_list = []
|
||||
easy_castle_fortress_levels_copy = easy_castle_fortress_levels.copy()
|
||||
world.random.shuffle(easy_castle_fortress_levels_copy)
|
||||
hard_castle_fortress_levels_copy = hard_castle_fortress_levels.copy()
|
||||
world.random.shuffle(hard_castle_fortress_levels_copy)
|
||||
easy_single_levels_copy = easy_single_levels.copy()
|
||||
world.random.shuffle(easy_single_levels_copy)
|
||||
hard_single_levels_copy = hard_single_levels.copy()
|
||||
world.random.shuffle(hard_single_levels_copy)
|
||||
easy_double_levels_copy = easy_double_levels.copy()
|
||||
world.random.shuffle(easy_double_levels_copy)
|
||||
hard_double_levels_copy = hard_double_levels.copy()
|
||||
world.random.shuffle(hard_double_levels_copy)
|
||||
switch_palace_levels_copy = switch_palace_levels.copy()
|
||||
world.random.shuffle(switch_palace_levels_copy)
|
||||
|
||||
# Yoshi's Island
|
||||
shuffled_level_list.append(0x03)
|
||||
shuffled_level_list.append(easy_single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x14)
|
||||
shuffled_level_list.append(easy_single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_castle_fortress_levels_copy.pop(0))
|
||||
|
||||
# Donut Plains
|
||||
shuffled_level_list.append(easy_double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x08)
|
||||
shuffled_level_list.append(easy_double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(easy_castle_fortress_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x28)
|
||||
shuffled_level_list.append(0x16)
|
||||
|
||||
single_levels_copy = (easy_single_levels_copy.copy() + hard_single_levels_copy.copy())
|
||||
world.random.shuffle(single_levels_copy)
|
||||
|
||||
castle_fortress_levels_copy = (easy_castle_fortress_levels_copy.copy() + hard_castle_fortress_levels_copy.copy())
|
||||
world.random.shuffle(castle_fortress_levels_copy)
|
||||
|
||||
double_levels_copy = (easy_double_levels_copy.copy() + hard_double_levels_copy.copy())
|
||||
world.random.shuffle(double_levels_copy)
|
||||
|
||||
# Vanilla Dome
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x3F)
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x2C)
|
||||
|
||||
# Twin Bridges
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x12)
|
||||
|
||||
# Forest of Illusion
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x45)
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x1E)
|
||||
|
||||
# Chocolate Island
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
|
||||
# Valley of Bowser
|
||||
shuffled_level_list.append(0x18)
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
shuffled_level_list.append(castle_fortress_levels_copy.pop(0))
|
||||
|
||||
# Front/Back Door
|
||||
if world.bowser_castle_doors[player] == "fast":
|
||||
shuffled_level_list.append(0x82)
|
||||
shuffled_level_list.append(0x32)
|
||||
elif world.bowser_castle_doors[player] == "slow":
|
||||
shuffled_level_list.append(0x31)
|
||||
shuffled_level_list.append(0x81)
|
||||
else:
|
||||
shuffled_level_list.append(0x31)
|
||||
shuffled_level_list.append(0x32)
|
||||
|
||||
shuffled_level_list.append(0x30)
|
||||
|
||||
# Star Road
|
||||
shuffled_level_list.append(0x5B)
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x53)
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x52)
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x57)
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x5C)
|
||||
shuffled_level_list.append(double_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x55)
|
||||
|
||||
# Special Zone
|
||||
shuffled_level_list.append(0x4D)
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(single_levels_copy.pop(0))
|
||||
shuffled_level_list.append(0x48)
|
||||
|
||||
return shuffled_level_list
|
||||
233
worlds/smw/Locations.py
Normal file
233
worlds/smw/Locations.py
Normal file
@@ -0,0 +1,233 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import Location
|
||||
from .Names import LocationName
|
||||
|
||||
|
||||
class SMWLocation(Location):
|
||||
game: str = "Super Mario World"
|
||||
|
||||
def __init__(self, player: int, name: str = '', address: int = None, parent=None, prog_byte: int = None, prog_bit: int = None):
|
||||
super().__init__(player, name, address, parent)
|
||||
self.progress_byte = prog_byte
|
||||
self.progress_bit = prog_bit
|
||||
|
||||
|
||||
level_location_table = {
|
||||
LocationName.yoshis_island_1_exit_1: 0xBC0000,
|
||||
LocationName.yoshis_island_2_exit_1: 0xBC0001,
|
||||
LocationName.yoshis_island_3_exit_1: 0xBC0002,
|
||||
LocationName.yoshis_island_4_exit_1: 0xBC0003,
|
||||
LocationName.yoshis_island_castle: 0xBC0004,
|
||||
LocationName.yoshis_island_koopaling: 0xBC00A0,
|
||||
|
||||
LocationName.yellow_switch_palace: 0xBC0005,
|
||||
|
||||
LocationName.donut_plains_1_exit_1: 0xBC0006,
|
||||
LocationName.donut_plains_1_exit_2: 0xBC0007,
|
||||
LocationName.donut_plains_2_exit_1: 0xBC0008,
|
||||
LocationName.donut_plains_2_exit_2: 0xBC0009,
|
||||
LocationName.donut_plains_3_exit_1: 0xBC000A,
|
||||
LocationName.donut_plains_4_exit_1: 0xBC000B,
|
||||
LocationName.donut_secret_1_exit_1: 0xBC000C,
|
||||
LocationName.donut_secret_1_exit_2: 0xBC000D,
|
||||
LocationName.donut_secret_2_exit_1: 0xBC0063,
|
||||
LocationName.donut_ghost_house_exit_1: 0xBC000E,
|
||||
LocationName.donut_ghost_house_exit_2: 0xBC000F,
|
||||
LocationName.donut_secret_house_exit_1: 0xBC0010,
|
||||
LocationName.donut_secret_house_exit_2: 0xBC0011,
|
||||
LocationName.donut_plains_castle: 0xBC0012,
|
||||
LocationName.donut_plains_koopaling: 0xBC00A1,
|
||||
|
||||
LocationName.green_switch_palace: 0xBC0013,
|
||||
|
||||
LocationName.vanilla_dome_1_exit_1: 0xBC0014,
|
||||
LocationName.vanilla_dome_1_exit_2: 0xBC0015,
|
||||
LocationName.vanilla_dome_2_exit_1: 0xBC0016,
|
||||
LocationName.vanilla_dome_2_exit_2: 0xBC0017,
|
||||
LocationName.vanilla_dome_3_exit_1: 0xBC0018,
|
||||
LocationName.vanilla_dome_4_exit_1: 0xBC0019,
|
||||
LocationName.vanilla_secret_1_exit_1: 0xBC001A,
|
||||
LocationName.vanilla_secret_1_exit_2: 0xBC001B,
|
||||
LocationName.vanilla_secret_2_exit_1: 0xBC001C,
|
||||
LocationName.vanilla_secret_3_exit_1: 0xBC001D,
|
||||
LocationName.vanilla_ghost_house_exit_1: 0xBC001E,
|
||||
LocationName.vanilla_fortress: 0xBC0020,
|
||||
LocationName.vanilla_reznor: 0xBC00B0,
|
||||
LocationName.vanilla_dome_castle: 0xBC0021,
|
||||
LocationName.vanilla_dome_koopaling: 0xBC00A2,
|
||||
|
||||
LocationName.red_switch_palace: 0xBC0022,
|
||||
|
||||
LocationName.butter_bridge_1_exit_1: 0xBC0023,
|
||||
LocationName.butter_bridge_2_exit_1: 0xBC0024,
|
||||
LocationName.cheese_bridge_exit_1: 0xBC0025,
|
||||
LocationName.cheese_bridge_exit_2: 0xBC0026,
|
||||
LocationName.cookie_mountain_exit_1: 0xBC0027,
|
||||
LocationName.soda_lake_exit_1: 0xBC0028,
|
||||
LocationName.twin_bridges_castle: 0xBC0029,
|
||||
LocationName.twin_bridges_koopaling: 0xBC00A3,
|
||||
|
||||
LocationName.forest_of_illusion_1_exit_1: 0xBC002A,
|
||||
LocationName.forest_of_illusion_1_exit_2: 0xBC002B,
|
||||
LocationName.forest_of_illusion_2_exit_1: 0xBC002C,
|
||||
LocationName.forest_of_illusion_2_exit_2: 0xBC002D,
|
||||
LocationName.forest_of_illusion_3_exit_1: 0xBC002E,
|
||||
LocationName.forest_of_illusion_3_exit_2: 0xBC002F,
|
||||
LocationName.forest_of_illusion_4_exit_1: 0xBC0030,
|
||||
LocationName.forest_of_illusion_4_exit_2: 0xBC0031,
|
||||
LocationName.forest_ghost_house_exit_1: 0xBC0032,
|
||||
LocationName.forest_ghost_house_exit_2: 0xBC0033,
|
||||
LocationName.forest_secret_exit_1: 0xBC0034,
|
||||
LocationName.forest_fortress: 0xBC0035,
|
||||
LocationName.forest_reznor: 0xBC00B1,
|
||||
LocationName.forest_castle: 0xBC0036,
|
||||
LocationName.forest_koopaling: 0xBC00A4,
|
||||
|
||||
LocationName.blue_switch_palace: 0xBC0037,
|
||||
|
||||
LocationName.chocolate_island_1_exit_1: 0xBC0038,
|
||||
LocationName.chocolate_island_2_exit_1: 0xBC0039,
|
||||
LocationName.chocolate_island_2_exit_2: 0xBC003A,
|
||||
LocationName.chocolate_island_3_exit_1: 0xBC003B,
|
||||
LocationName.chocolate_island_3_exit_2: 0xBC003C,
|
||||
LocationName.chocolate_island_4_exit_1: 0xBC003D,
|
||||
LocationName.chocolate_island_5_exit_1: 0xBC003E,
|
||||
LocationName.chocolate_ghost_house_exit_1: 0xBC003F,
|
||||
LocationName.chocolate_secret_exit_1: 0xBC0041,
|
||||
LocationName.chocolate_fortress: 0xBC0042,
|
||||
LocationName.chocolate_reznor: 0xBC00B2,
|
||||
LocationName.chocolate_castle: 0xBC0043,
|
||||
LocationName.chocolate_koopaling: 0xBC00A5,
|
||||
|
||||
LocationName.sunken_ghost_ship: 0xBC0044,
|
||||
|
||||
LocationName.valley_of_bowser_1_exit_1: 0xBC0045,
|
||||
LocationName.valley_of_bowser_2_exit_1: 0xBC0046,
|
||||
LocationName.valley_of_bowser_2_exit_2: 0xBC0047,
|
||||
LocationName.valley_of_bowser_3_exit_1: 0xBC0048,
|
||||
LocationName.valley_of_bowser_4_exit_1: 0xBC0049,
|
||||
LocationName.valley_of_bowser_4_exit_2: 0xBC004A,
|
||||
LocationName.valley_ghost_house_exit_1: 0xBC004B,
|
||||
LocationName.valley_ghost_house_exit_2: 0xBC004C,
|
||||
LocationName.valley_fortress: 0xBC004E,
|
||||
LocationName.valley_reznor: 0xBC00B3,
|
||||
LocationName.valley_castle: 0xBC004F,
|
||||
LocationName.valley_koopaling: 0xBC00A6,
|
||||
|
||||
LocationName.star_road_1_exit_1: 0xBC0051,
|
||||
LocationName.star_road_1_exit_2: 0xBC0052,
|
||||
LocationName.star_road_2_exit_1: 0xBC0053,
|
||||
LocationName.star_road_2_exit_2: 0xBC0054,
|
||||
LocationName.star_road_3_exit_1: 0xBC0055,
|
||||
LocationName.star_road_3_exit_2: 0xBC0056,
|
||||
LocationName.star_road_4_exit_1: 0xBC0057,
|
||||
LocationName.star_road_4_exit_2: 0xBC0058,
|
||||
LocationName.star_road_5_exit_1: 0xBC0059,
|
||||
LocationName.star_road_5_exit_2: 0xBC005A,
|
||||
|
||||
LocationName.special_zone_1_exit_1: 0xBC005B,
|
||||
LocationName.special_zone_2_exit_1: 0xBC005C,
|
||||
LocationName.special_zone_3_exit_1: 0xBC005D,
|
||||
LocationName.special_zone_4_exit_1: 0xBC005E,
|
||||
LocationName.special_zone_5_exit_1: 0xBC005F,
|
||||
LocationName.special_zone_6_exit_1: 0xBC0060,
|
||||
LocationName.special_zone_7_exit_1: 0xBC0061,
|
||||
LocationName.special_zone_8_exit_1: 0xBC0062,
|
||||
}
|
||||
|
||||
dragon_coin_location_table = {
|
||||
LocationName.yoshis_island_1_dragon: 0xBC0100,
|
||||
LocationName.yoshis_island_2_dragon: 0xBC0101,
|
||||
LocationName.yoshis_island_3_dragon: 0xBC0102,
|
||||
LocationName.yoshis_island_4_dragon: 0xBC0103,
|
||||
|
||||
LocationName.donut_plains_1_dragon: 0xBC0106,
|
||||
LocationName.donut_plains_2_dragon: 0xBC0108,
|
||||
LocationName.donut_plains_3_dragon: 0xBC010A,
|
||||
LocationName.donut_plains_4_dragon: 0xBC010B,
|
||||
LocationName.donut_secret_1_dragon: 0xBC010C,
|
||||
LocationName.donut_secret_2_dragon: 0xBC010D,
|
||||
|
||||
LocationName.vanilla_dome_1_dragon: 0xBC0114,
|
||||
LocationName.vanilla_dome_2_dragon: 0xBC0116,
|
||||
LocationName.vanilla_dome_3_dragon: 0xBC0118,
|
||||
LocationName.vanilla_dome_4_dragon: 0xBC0119,
|
||||
LocationName.vanilla_secret_1_dragon: 0xBC011A,
|
||||
LocationName.vanilla_secret_2_dragon: 0xBC011C,
|
||||
LocationName.vanilla_secret_3_dragon: 0xBC011D,
|
||||
LocationName.vanilla_ghost_house_dragon: 0xBC011E,
|
||||
|
||||
LocationName.butter_bridge_1_dragon: 0xBC0123,
|
||||
LocationName.butter_bridge_2_dragon: 0xBC0124,
|
||||
LocationName.cheese_bridge_dragon: 0xBC0125,
|
||||
LocationName.cookie_mountain_dragon: 0xBC0127,
|
||||
LocationName.soda_lake_dragon: 0xBC0128,
|
||||
|
||||
LocationName.forest_of_illusion_2_dragon: 0xBC012C,
|
||||
LocationName.forest_of_illusion_3_dragon: 0xBC012E,
|
||||
LocationName.forest_of_illusion_4_dragon: 0xBC0130,
|
||||
LocationName.forest_ghost_house_dragon: 0xBC0132,
|
||||
LocationName.forest_secret_dragon: 0xBC0134,
|
||||
LocationName.forest_castle_dragon: 0xBC0136,
|
||||
|
||||
LocationName.chocolate_island_1_dragon: 0xBC0138,
|
||||
LocationName.chocolate_island_2_dragon: 0xBC0139,
|
||||
LocationName.chocolate_island_3_dragon: 0xBC013B,
|
||||
LocationName.chocolate_island_4_dragon: 0xBC013D,
|
||||
LocationName.chocolate_island_5_dragon: 0xBC013E,
|
||||
|
||||
LocationName.sunken_ghost_ship_dragon: 0xBC0144,
|
||||
|
||||
LocationName.valley_of_bowser_1_dragon: 0xBC0145,
|
||||
LocationName.valley_of_bowser_2_dragon: 0xBC0146,
|
||||
LocationName.valley_of_bowser_3_dragon: 0xBC0148,
|
||||
LocationName.valley_ghost_house_dragon: 0xBC014B,
|
||||
LocationName.valley_castle_dragon: 0xBC014F,
|
||||
|
||||
LocationName.star_road_1_dragon: 0xBC0151,
|
||||
|
||||
LocationName.special_zone_1_dragon: 0xBC015B,
|
||||
LocationName.special_zone_2_dragon: 0xBC015C,
|
||||
LocationName.special_zone_3_dragon: 0xBC015D,
|
||||
LocationName.special_zone_4_dragon: 0xBC015E,
|
||||
LocationName.special_zone_5_dragon: 0xBC015F,
|
||||
LocationName.special_zone_6_dragon: 0xBC0160,
|
||||
LocationName.special_zone_7_dragon: 0xBC0161,
|
||||
LocationName.special_zone_8_dragon: 0xBC0162,
|
||||
}
|
||||
|
||||
bowser_location_table = {
|
||||
LocationName.bowser: 0xBC0200,
|
||||
}
|
||||
|
||||
yoshi_house_location_table = {
|
||||
LocationName.yoshis_house: 0xBC0201,
|
||||
}
|
||||
|
||||
all_locations = {
|
||||
**level_location_table,
|
||||
**dragon_coin_location_table,
|
||||
**bowser_location_table,
|
||||
**yoshi_house_location_table,
|
||||
}
|
||||
|
||||
location_table = {}
|
||||
|
||||
|
||||
def setup_locations(world, player: int):
|
||||
location_table = {**level_location_table}
|
||||
|
||||
# Dragon Coins here
|
||||
if world.dragon_coin_checks[player].value:
|
||||
location_table.update({**dragon_coin_location_table})
|
||||
|
||||
if world.goal[player] == "yoshi_egg_hunt":
|
||||
location_table.update({**yoshi_house_location_table})
|
||||
else:
|
||||
location_table.update({**bowser_location_table})
|
||||
|
||||
return location_table
|
||||
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {id: name for name, _ in all_locations.items()}
|
||||
32
worlds/smw/Names/ItemName.py
Normal file
32
worlds/smw/Names/ItemName.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Junk Definitions
|
||||
one_up_mushroom = "1-Up Mushroom"
|
||||
|
||||
# Collectable Definitions
|
||||
yoshi_egg = "Yoshi Egg"
|
||||
|
||||
# Upgrade Definitions
|
||||
mario_run = "Run"
|
||||
mario_carry = "Carry"
|
||||
mario_swim = "Swim"
|
||||
mario_spin_jump = "Spin Jump"
|
||||
mario_climb = "Climb"
|
||||
yoshi_activate = "Yoshi"
|
||||
p_switch = "P-Switch"
|
||||
p_balloon = "P-Balloon"
|
||||
progressive_powerup = "Progressive Powerup"
|
||||
super_star_active = "Super Star Activate"
|
||||
|
||||
# Switch Palace Definitions
|
||||
yellow_switch_palace = "Yellow Switch Palace"
|
||||
green_switch_palace = "Green Switch Palace"
|
||||
red_switch_palace = "Red Switch Palace"
|
||||
blue_switch_palace = "Blue Switch Palace"
|
||||
|
||||
# Trap Definitions
|
||||
ice_trap = "Ice Trap"
|
||||
stun_trap = "Stun Trap"
|
||||
literature_trap = "Literature Trap"
|
||||
|
||||
# Other Definitions
|
||||
victory = "The Princess"
|
||||
koopaling = "Boss Token"
|
||||
52
worlds/smw/Names/LiteratureTrap.py
Normal file
52
worlds/smw/Names/LiteratureTrap.py
Normal file
@@ -0,0 +1,52 @@
|
||||
lit_trap_text_list = [
|
||||
[[0x8, 0x1f, 0x4c, 0x54, 0x52, 0x53, 0x1f, 0x4d, 0x4e, 0x53, 0x1f, 0x45, 0x44, 0x40, 0x51, 0x1b, 0x9f, 0x5, 0x44, 0x40, 0x51, 0x1f, 0x48, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4c, 0x48, 0x4d, 0x43, 0x1c, 0x4a, 0x48, 0x4b, 0x4b, 0x44, 0x51, 0x1b, 0x1f, 0x5, 0x44, 0x40, 0x51, 0x9f, 0x48, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4b, 0x48, 0x53, 0x53, 0x4b, 0x44, 0x1c, 0x43, 0x44, 0x40, 0x53, 0x47, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x9f, 0x41, 0x51, 0x48, 0x4d, 0x46, 0x52, 0x1f, 0x40, 0x41, 0x4e, 0x54, 0x53, 0x1f, 0x53, 0x4e, 0x53, 0x40, 0xcb, 0x4e, 0x41, 0x4b, 0x48, 0x53, 0x44, 0x51, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1b, 0x1f, 0x8, 0x9f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x45, 0x40, 0x42, 0x44, 0x1f, 0x4c, 0x58, 0x1f, 0x45, 0x44, 0x40, 0x51, 0x9b, ], [0x8, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x4f, 0x44, 0x51, 0x4c, 0x48, 0x53, 0x1f, 0x48, 0x53, 0x9f, 0x53, 0x4e, 0x1f, 0x4f, 0x40, 0x52, 0x52, 0x1f, 0x4e, 0x55, 0x44, 0x51, 0x1f, 0x4c, 0x44, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x1f, 0x4c, 0x44, 0x1b, 0x9f, 0x0, 0x4d, 0x43, 0x1f, 0x56, 0x47, 0x44, 0x4d, 0x1f, 0x48, 0x53, 0x1f, 0x47, 0x40, 0x52, 0x9f, 0x46, 0x4e, 0x4d, 0x44, 0x1f, 0x4f, 0x40, 0x52, 0x53, 0x1f, 0x8, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x9f, 0x53, 0x54, 0x51, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x48, 0x4d, 0x4d, 0x44, 0x51, 0x1f, 0x44, 0x58, 0xc4, 0x53, 0x4e, 0x1f, 0x52, 0x44, 0x44, 0x1f, 0x48, 0x53, 0x52, 0x1f, 0x4f, 0x40, 0x53, 0x47, 0x1b, 0x9f, 0x16, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x45, 0x44, 0x40, 0x51, 0x1f, 0x47, 0x40, 0xd2, ], [0x46, 0x4e, 0x4d, 0x44, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x9f, 0x41, 0x44, 0x1f, 0x4d, 0x4e, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1b, 0x1f, 0xe, 0x4d, 0x4b, 0x58, 0x1f, 0x88, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x51, 0x44, 0x4c, 0x40, 0x48, 0x4d, 0x1b, 0x9f, 0x1c, 0x7, 0x44, 0x51, 0x41, 0x44, 0x51, 0x53, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x0, 0x41, 0x4e, 0x54, 0x53, 0x1f, 0x53, 0x47, 0x51, 0x44, 0x44, 0x1f, 0x53, 0x47, 0x48, 0x4d, 0x46, 0xd2, 0x8, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x40, 0x41, 0x52, 0x4e, 0x4b, 0x54, 0x53, 0x44, 0x4b, 0x58, 0x9f, 0x4f, 0x4e, 0x52, 0x48, 0x53, 0x48, 0x55, 0x44, 0x1b, 0x1f, 0x5, 0x48, 0x51, 0x52, 0x53, 0x1d, 0x9f, 0x4, 0x43, 0x56, 0x40, 0x51, 0x43, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x40, 0x9f, 0x55, 0x40, 0x4c, 0x4f, 0x48, 0x51, 0x44, 0x1b, 0x1f, 0x12, 0x44, 0x42, 0x4e, 0x4d, 0x43, 0x1d, 0x9f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x40, 0x1f, 0x4f, 0x40, 0x51, 0x53, 0x9f, 0x4e, 0x45, 0x1f, 0x47, 0x48, 0x4c, 0x1f, 0x1c, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x8, 0x9f, 0x43, 0x48, 0x43, 0x4d, 0x5d, 0x53, 0x1f, 0x4a, 0x4d, 0x4e, 0x56, 0x1f, 0x47, 0x4e, 0x56, 0x9f, ], [0x4f, 0x4e, 0x53, 0x44, 0x4d, 0x53, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x4f, 0x40, 0x51, 0x53, 0x9f, 0x4c, 0x48, 0x46, 0x47, 0x53, 0x1f, 0x41, 0x44, 0x1f, 0x1c, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x9f, 0x53, 0x47, 0x48, 0x51, 0x52, 0x53, 0x44, 0x43, 0x1f, 0x45, 0x4e, 0x51, 0x1f, 0x4c, 0x58, 0x9f, 0x41, 0x4b, 0x4e, 0x4e, 0x43, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x48, 0x51, 0x43, 0x1d, 0x9f, 0x8, 0x1f, 0x56, 0x40, 0x52, 0x9f, 0x54, 0x4d, 0x42, 0x4e, 0x4d, 0x43, 0x48, 0x53, 0x48, 0x4e, 0x4d, 0x40, 0x4b, 0x4b, 0x58, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x48, 0x51, 0x51, 0x44, 0x55, 0x4e, 0x42, 0x40, 0x41, 0x4b, 0x58, 0x1f, 0x48, 0xcd, 0x4b, 0x4e, 0x55, 0x44, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x47, 0x48, 0x4c, 0x1b, 0x9f, ], [0x1c, 0xc, 0x44, 0x58, 0x44, 0x51, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x12, 0x40, 0x58, 0x1a, 0x1f, 0x8, 0x1f, 0x4b, 0x48, 0x4a, 0x44, 0x1f, 0x46, 0x51, 0x44, 0x44, 0x4d, 0x9f, 0x44, 0x46, 0x46, 0x52, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x47, 0x40, 0x4c, 0x1a, 0x1f, 0x8, 0x9f, 0x43, 0x4e, 0x1a, 0x1f, 0x8, 0x1f, 0x4b, 0x48, 0x4a, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1d, 0x9f, 0x12, 0x40, 0x4c, 0x1c, 0x8, 0x1c, 0x40, 0x4c, 0x1a, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x8, 0x9f, 0x56, 0x4e, 0x54, 0x4b, 0x43, 0x1f, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x48, 0x4d, 0x9f, 0x40, 0x1f, 0x41, 0x4e, 0x40, 0x53, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x8, 0x9f, 0x56, 0x4e, 0x54, 0x4b, 0x43, 0x1f, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x9f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x40, 0x1f, 0x46, 0x4e, 0x40, 0x53, 0x1b, 0x1b, 0x1b, 0x1f, 0x0, 0x4d, 0xc3, ], [0x8, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x48, 0xcd, 0x53, 0x47, 0x44, 0x1f, 0x51, 0x40, 0x48, 0x4d, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x48, 0x4d, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x43, 0x40, 0x51, 0x4a, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x4e, 0x4d, 0x1f, 0xc0, 0x53, 0x51, 0x40, 0x48, 0x4d, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0x9f, 0x42, 0x40, 0x51, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0x9f, 0x53, 0x51, 0x44, 0x44, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x58, 0x1f, 0x40, 0x51, 0x44, 0x1f, 0x52, 0x4e, 0x9f, 0x46, 0x4e, 0x4e, 0x43, 0x1d, 0x1f, 0x52, 0x4e, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x1d, 0x1f, 0x58, 0x4e, 0xd4, 0x52, 0x44, 0x44, 0x1a, 0x1f, 0x12, 0x4e, 0x1f, 0x8, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x44, 0x40, 0xd3, ], [0x53, 0x47, 0x44, 0x4c, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0x1f, 0x41, 0x4e, 0x57, 0x1b, 0x1f, 0x0, 0x4d, 0xc3, 0x8, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x9f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x40, 0x1f, 0x45, 0x4e, 0x57, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x8, 0x9f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x48, 0x4d, 0x1f, 0xc0, 0x47, 0x4e, 0x54, 0x52, 0x44, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x8, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x9f, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x40, 0x9f, 0x4c, 0x4e, 0x54, 0x52, 0x44, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x8, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x9f, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x40, 0x4d, 0x43, 0x9f, ], [0x53, 0x47, 0x44, 0x51, 0x44, 0x1b, 0x1f, 0x12, 0x40, 0x58, 0x1a, 0x1f, 0x8, 0x1f, 0x56, 0x48, 0x4b, 0xcb, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x40, 0x4d, 0x58, 0x56, 0x47, 0x44, 0x51, 0x44, 0x9a, 0x8, 0x1f, 0x43, 0x4e, 0x1f, 0x52, 0x4e, 0x1f, 0x4b, 0x48, 0x4a, 0x44, 0x1f, 0x46, 0x51, 0x44, 0x44, 0xcd, 0x44, 0x46, 0x46, 0x52, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x47, 0x40, 0x4c, 0x1a, 0x9f, 0x13, 0x47, 0x40, 0x4d, 0x4a, 0x1f, 0x58, 0x4e, 0x54, 0x1a, 0x1f, 0x13, 0x47, 0x40, 0x4d, 0x4a, 0x9f, 0x58, 0x4e, 0x54, 0x1d, 0x1f, 0x12, 0x40, 0x4c, 0x1c, 0x8, 0x1c, 0x40, 0x4c, 0x1a, 0x9f, 0x1c, 0x12, 0x44, 0x54, 0x52, 0x52, 0x1f, 0x9f, 0x9f, ]],
|
||||
[[0x1, 0x54, 0x53, 0x1d, 0x1f, 0x52, 0x4e, 0x45, 0x53, 0x1a, 0x1f, 0x56, 0x47, 0x40, 0x53, 0x9f, 0x4b, 0x48, 0x46, 0x47, 0x53, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x9f, 0x58, 0x4e, 0x4d, 0x43, 0x44, 0x51, 0x1f, 0x56, 0x48, 0x4d, 0x43, 0x4e, 0x56, 0x9f, 0x41, 0x51, 0x44, 0x40, 0x4a, 0x52, 0x1e, 0x1f, 0x8, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x44, 0x40, 0x52, 0x53, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x9, 0x54, 0x4b, 0x48, 0x44, 0x53, 0x9f, 0x48, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x54, 0x4d, 0x1b, 0x1f, 0x0, 0x51, 0x48, 0x52, 0x44, 0x9d, 0x45, 0x40, 0x48, 0x51, 0x1f, 0x52, 0x54, 0x4d, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x4a, 0x48, 0x4b, 0xcb, 0x53, 0x47, 0x44, 0x1f, 0x44, 0x4d, 0x55, 0x48, 0x4e, 0x54, 0x52, 0x1f, 0x4c, 0x4e, 0x4e, 0x4d, 0x1d, 0x9f, ], [0x16, 0x47, 0x4e, 0x1f, 0x48, 0x52, 0x1f, 0x40, 0x4b, 0x51, 0x44, 0x40, 0x43, 0x58, 0x9f, 0x52, 0x48, 0x42, 0x4a, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x4f, 0x40, 0x4b, 0x44, 0x1f, 0x56, 0x48, 0x53, 0xc7, 0x46, 0x51, 0x48, 0x44, 0x45, 0x1d, 0x1f, 0x13, 0x47, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x4e, 0x54, 0x9f, 0x47, 0x44, 0x51, 0x1f, 0x4c, 0x40, 0x48, 0x43, 0x1f, 0x40, 0x51, 0x53, 0x1f, 0x45, 0x40, 0x51, 0x9f, 0x4c, 0x4e, 0x51, 0x44, 0x1f, 0x45, 0x40, 0x48, 0x51, 0x1f, 0x53, 0x47, 0x40, 0x4d, 0x9f, 0x52, 0x47, 0x44, 0x1b, 0x1f, 0x1, 0x44, 0x1f, 0x4d, 0x4e, 0x53, 0x1f, 0x47, 0x44, 0x51, 0x9f, 0x4c, 0x40, 0x48, 0x43, 0x1d, 0x1f, 0x52, 0x48, 0x4d, 0x42, 0x44, 0x1f, 0x52, 0x47, 0x44, 0x1f, 0x48, 0xd2, 0x44, 0x4d, 0x55, 0x48, 0x4e, 0x54, 0x52, 0x1b, 0x1f, 0x7, 0x44, 0x51, 0x9f, ], [0x55, 0x44, 0x52, 0x53, 0x40, 0x4b, 0x1f, 0x4b, 0x48, 0x55, 0x44, 0x51, 0x58, 0x1f, 0x48, 0x52, 0x9f, 0x41, 0x54, 0x53, 0x1f, 0x52, 0x48, 0x42, 0x4a, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x46, 0x51, 0x44, 0x44, 0xcd, 0x0, 0x4d, 0x43, 0x1f, 0x4d, 0x4e, 0x4d, 0x44, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x45, 0x4e, 0x4e, 0x4b, 0xd2, 0x43, 0x4e, 0x1f, 0x56, 0x44, 0x40, 0x51, 0x1f, 0x48, 0x53, 0x1b, 0x1f, 0x42, 0x40, 0x52, 0x53, 0x9f, 0x48, 0x53, 0x1f, 0x4e, 0x45, 0x45, 0x1b, 0x1f, 0x8, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x4c, 0x58, 0x9f, 0x4b, 0x40, 0x43, 0x58, 0x1d, 0x1f, 0xe, 0x1d, 0x1f, 0x48, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x4c, 0x58, 0x9f, 0x4b, 0x4e, 0x55, 0x44, 0x1a, 0x1f, 0xe, 0x1d, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x52, 0x47, 0x44, 0x9f, 0x4a, 0x4d, 0x44, 0x56, 0x1f, 0x52, 0x47, 0x44, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x1a, 0x9f, ], [0x1c, 0x12, 0x47, 0x40, 0x4a, 0x44, 0x52, 0x4f, 0x44, 0x40, 0x51, 0x44, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x8, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x41, 0x44, 0x52, 0x53, 0x1f, 0x4e, 0xc5, 0x53, 0x48, 0x4c, 0x44, 0x52, 0x1d, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x56, 0x4e, 0x51, 0x52, 0x53, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x48, 0x4c, 0x44, 0x52, 0x1d, 0x1f, 0x48, 0xd3, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x40, 0x46, 0x44, 0x1f, 0x4e, 0x45, 0x9f, 0x56, 0x48, 0x52, 0x43, 0x4e, 0x4c, 0x1d, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0xc4, 0x40, 0x46, 0x44, 0x1f, 0x4e, 0x45, 0x9f, 0x45, 0x4e, 0x4e, 0x4b, 0x48, 0x52, 0x47, 0x4d, 0x44, 0x52, 0x52, 0x1d, 0x1f, 0x48, 0x53, 0x9f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x44, 0x4f, 0x4e, 0x42, 0x47, 0x1f, 0x4e, 0x45, 0x9f, ], [0x41, 0x44, 0x4b, 0x48, 0x44, 0x45, 0x1d, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0xc4, 0x44, 0x4f, 0x4e, 0x42, 0x47, 0x1f, 0x4e, 0x45, 0x9f, 0x48, 0x4d, 0x42, 0x51, 0x44, 0x43, 0x54, 0x4b, 0x48, 0x53, 0x58, 0x1d, 0x1f, 0x48, 0x53, 0x9f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x44, 0x40, 0x52, 0x4e, 0x4d, 0x1f, 0x4e, 0x45, 0x9f, 0x4b, 0x48, 0x46, 0x47, 0x53, 0x1d, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x52, 0x44, 0x40, 0x52, 0x4e, 0x4d, 0x1f, 0x4e, 0x45, 0x9f, 0x43, 0x40, 0x51, 0x4a, 0x4d, 0x44, 0x52, 0x52, 0x1d, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x4f, 0x51, 0x48, 0x4d, 0x46, 0x1f, 0x4e, 0x45, 0x9f, ], [0x47, 0x4e, 0x4f, 0x44, 0x1d, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x56, 0x48, 0x4d, 0x53, 0x44, 0x51, 0x1f, 0x4e, 0x45, 0x1f, 0x43, 0x44, 0x52, 0x4f, 0x40, 0x48, 0x51, 0x9b, 0x1c, 0x3, 0x48, 0x42, 0x4a, 0x44, 0x4d, 0x52, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0xc, 0x40, 0x51, 0x4b, 0x44, 0x58, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x43, 0x44, 0x40, 0x43, 0x1d, 0x9f, 0x53, 0x4e, 0x1f, 0x41, 0x44, 0x46, 0x48, 0x4d, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x1b, 0x9f, 0x13, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x48, 0x52, 0x1f, 0x4d, 0x4e, 0x1f, 0x43, 0x4e, 0x54, 0x41, 0x53, 0x9f, 0x56, 0x47, 0x40, 0x53, 0x44, 0x55, 0x44, 0x51, 0x1d, 0x1f, 0x40, 0x41, 0x4e, 0x54, 0x53, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x1f, 0x51, 0x44, 0x46, 0x48, 0x52, 0x53, 0x44, 0xd1, 0x4e, 0x45, 0x1f, 0x47, 0x48, 0x52, 0x1f, 0x41, 0x54, 0x51, 0x48, 0x40, 0x4b, 0x1f, 0x56, 0x40, 0x52, 0x9f, 0x52, 0x48, 0x46, 0x4d, 0x44, 0x43, 0x1f, 0x41, 0x58, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x42, 0x4b, 0x44, 0x51, 0x46, 0x58, 0x4c, 0x40, 0x4d, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x9f, ], [0x42, 0x4b, 0x44, 0x51, 0x4a, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x54, 0x4d, 0x43, 0x44, 0x51, 0x53, 0x40, 0x4a, 0x44, 0x51, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x42, 0x47, 0x48, 0x44, 0x45, 0x1f, 0x4c, 0x4e, 0x54, 0x51, 0x4d, 0x44, 0x51, 0x9b, 0x12, 0x42, 0x51, 0x4e, 0x4e, 0x46, 0x44, 0x1f, 0x52, 0x48, 0x46, 0x4d, 0x44, 0x43, 0x1f, 0x48, 0x53, 0x9b, 0x40, 0x4d, 0x43, 0x1f, 0x12, 0x42, 0x51, 0x4e, 0x4e, 0x46, 0x44, 0x5d, 0x52, 0x1f, 0x4d, 0x40, 0x4c, 0xc4, 0x56, 0x40, 0x52, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x1f, 0x54, 0x4f, 0x4e, 0x4d, 0x9f, 0x5d, 0x42, 0x47, 0x40, 0x4d, 0x46, 0x44, 0x1d, 0x1f, 0x45, 0x4e, 0x51, 0x9f, 0x40, 0x4d, 0x58, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1f, 0x47, 0x44, 0x1f, 0x42, 0x47, 0x4e, 0x52, 0x44, 0x9f, ], [0x53, 0x4e, 0x1f, 0x4f, 0x54, 0x53, 0x1f, 0x47, 0x48, 0x52, 0x1f, 0x47, 0x40, 0x4d, 0x43, 0x9f, 0x53, 0x4e, 0x1b, 0x1f, 0xe, 0x4b, 0x43, 0x1f, 0xc, 0x40, 0x51, 0x4b, 0x44, 0x58, 0x1f, 0x56, 0x40, 0xd2, 0x40, 0x52, 0x1f, 0x43, 0x44, 0x40, 0x43, 0x1f, 0x40, 0x52, 0x1f, 0x40, 0x9f, 0x43, 0x4e, 0x4e, 0x51, 0x1c, 0x4d, 0x40, 0x48, 0x4b, 0x1b, 0x9f, 0x1c, 0x3, 0x48, 0x42, 0x4a, 0x44, 0x4d, 0x52, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0xc, 0x40, 0x4d, 0x58, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x4b, 0x48, 0x55, 0x44, 0x9f, 0x43, 0x44, 0x52, 0x44, 0x51, 0x55, 0x44, 0x1f, 0x43, 0x44, 0x40, 0x53, 0x47, 0x1b, 0x1f, 0x0, 0x4d, 0xc3, 0x52, 0x4e, 0x4c, 0x44, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x43, 0x48, 0x44, 0x9f, 0x43, 0x44, 0x52, 0x44, 0x51, 0x55, 0x44, 0x1f, 0x4b, 0x48, 0x45, 0x44, 0x1b, 0x1f, 0x2, 0x40, 0x4d, 0x9f, 0x58, 0x4e, 0x54, 0x1f, 0x46, 0x48, 0x55, 0x44, 0x1f, 0x48, 0x53, 0x1f, 0x53, 0x4e, 0x9f, 0x53, 0x47, 0x44, 0x4c, 0x1e, 0x1f, 0x13, 0x47, 0x44, 0x4d, 0x1f, 0x43, 0x4e, 0x1f, 0x4d, 0x4e, 0x53, 0x9f, 0x41, 0x44, 0x1f, 0x53, 0x4e, 0x4e, 0x1f, 0x44, 0x40, 0x46, 0x44, 0x51, 0x1f, 0x53, 0x4e, 0x9f, 0x43, 0x44, 0x40, 0x4b, 0x1f, 0x4e, 0x54, 0x53, 0x1f, 0x43, 0x44, 0x40, 0x53, 0x47, 0x1f, 0x48, 0x4d, 0x9f, ], [0x49, 0x54, 0x43, 0x46, 0x44, 0x4c, 0x44, 0x4d, 0x53, 0x1b, 0x1f, 0x5, 0x4e, 0x51, 0x9f, 0x44, 0x55, 0x44, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x55, 0x44, 0x51, 0x58, 0x1f, 0x56, 0x48, 0x52, 0xc4, 0x42, 0x40, 0x4d, 0x4d, 0x4e, 0x53, 0x1f, 0x52, 0x44, 0x44, 0x1f, 0x40, 0x4b, 0x4b, 0x9f, 0x44, 0x4d, 0x43, 0x52, 0x1b, 0x1f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x8, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x40, 0x1f, 0x53, 0x51, 0x54, 0x53, 0x47, 0x9f, 0x54, 0x4d, 0x48, 0x55, 0x44, 0x51, 0x52, 0x40, 0x4b, 0x4b, 0x58, 0x9f, 0x40, 0x42, 0x4a, 0x4d, 0x4e, 0x56, 0x4b, 0x44, 0x43, 0x46, 0x44, 0x43, 0x1d, 0x1f, 0x53, 0x47, 0x40, 0xd3, 0x40, 0x1f, 0x52, 0x48, 0x4d, 0x46, 0x4b, 0x44, 0x1f, 0x4c, 0x40, 0x4d, 0x1f, 0x48, 0x4d, 0x9f, 0x4f, 0x4e, 0x52, 0x52, 0x44, 0x52, 0x52, 0x48, 0x4e, 0x4d, 0x1f, 0x4e, 0x45, 0x1f, 0x40, 0x9f, 0x46, 0x4e, 0x4e, 0x43, 0x1f, 0x45, 0x4e, 0x51, 0x53, 0x54, 0x4d, 0x44, 0x1d, 0x1f, 0x4c, 0x54, 0x52, 0xd3, 0x41, 0x44, 0x1f, 0x48, 0x4d, 0x1f, 0x56, 0x40, 0x4d, 0x53, 0x1f, 0x4e, 0x45, 0x1f, 0x40, 0x9f, 0x56, 0x48, 0x45, 0x44, 0x1b, 0x1f, 0x1c, 0x0, 0x54, 0x52, 0x53, 0x44, 0x4d, 0x1f, 0x9f, ]],
|
||||
[[0x13, 0x47, 0x44, 0x1f, 0x53, 0x51, 0x54, 0x53, 0x47, 0x1f, 0x40, 0x4b, 0x56, 0x40, 0x58, 0x52, 0x9f, 0x42, 0x40, 0x51, 0x51, 0x48, 0x44, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x40, 0x4c, 0x41, 0x48, 0x46, 0x54, 0x48, 0x53, 0x58, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x56, 0x4e, 0x51, 0x43, 0x52, 0x1f, 0x54, 0x52, 0x44, 0x43, 0x1f, 0x53, 0x4e, 0x9f, 0x44, 0x57, 0x4f, 0x51, 0x44, 0x52, 0x52, 0x1f, 0x48, 0x53, 0x1b, 0x9f, 0x1c, 0x7, 0x44, 0x51, 0x41, 0x44, 0x51, 0x53, 0x1f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x5d, 0x8, 0x1f, 0x43, 0x40, 0x51, 0x44, 0x52, 0x40, 0x58, 0x1f, 0x58, 0x4e, 0x54, 0x9f, 0x47, 0x40, 0x55, 0x44, 0x4d, 0x5d, 0x53, 0x1f, 0x47, 0x40, 0x43, 0x1f, 0x4c, 0x54, 0x42, 0x47, 0x9f, 0x4f, 0x51, 0x40, 0x42, 0x53, 0x48, 0x42, 0x44, 0x1d, 0x5d, 0x1f, 0x52, 0x40, 0x48, 0x43, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x10, 0x54, 0x44, 0x44, 0x4d, 0x1b, 0x1f, 0x5d, 0x16, 0x47, 0x44, 0x4d, 0x1f, 0x88, 0x56, 0x40, 0x52, 0x1f, 0x58, 0x4e, 0x54, 0x51, 0x1f, 0x40, 0x46, 0x44, 0x1d, 0x1f, 0x8, 0x9f, 0x40, 0x4b, 0x56, 0x40, 0x58, 0x52, 0x1f, 0x43, 0x48, 0x43, 0x1f, 0x48, 0x53, 0x1f, 0x45, 0x4e, 0x51, 0x9f, 0x47, 0x40, 0x4b, 0x45, 0x1c, 0x40, 0x4d, 0x1c, 0x47, 0x4e, 0x54, 0x51, 0x1f, 0x40, 0x9f, 0x43, 0x40, 0x58, 0x1b, 0x1f, 0x16, 0x47, 0x58, 0x1d, 0x9f, ], [0x52, 0x4e, 0x4c, 0x44, 0x53, 0x48, 0x4c, 0x44, 0x52, 0x1f, 0x8, 0x5d, 0x55, 0x44, 0x9f, 0x41, 0x44, 0x4b, 0x48, 0x44, 0x55, 0x44, 0x43, 0x1f, 0x40, 0x52, 0x1f, 0x4c, 0x40, 0x4d, 0x58, 0x9f, 0x40, 0x52, 0x1f, 0x52, 0x48, 0x57, 0x1f, 0x48, 0x4c, 0x4f, 0x4e, 0x52, 0x52, 0x48, 0x41, 0x4b, 0x44, 0x9f, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x52, 0x1f, 0x41, 0x44, 0x45, 0x4e, 0x51, 0x44, 0x9f, 0x41, 0x51, 0x44, 0x40, 0x4a, 0x45, 0x40, 0x52, 0x53, 0x1b, 0x5d, 0x9f, 0x1c, 0x2, 0x40, 0x51, 0x51, 0x4e, 0x4b, 0x4b, 0x1f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0xb, 0x48, 0x45, 0x44, 0x1d, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x48, 0x53, 0x52, 0x9f, 0x51, 0x54, 0x4b, 0x44, 0x52, 0x1d, 0x1f, 0x48, 0x53, 0x52, 0x9f, 0x4e, 0x41, 0x4b, 0x48, 0x46, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x52, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x48, 0x53, 0x52, 0x1f, 0x45, 0x51, 0x44, 0x44, 0x43, 0x4e, 0x4c, 0x52, 0x1d, 0x1f, 0x48, 0x52, 0x9f, 0x4b, 0x48, 0x4a, 0x44, 0x1f, 0x40, 0x1f, 0x52, 0x4e, 0x4d, 0x4d, 0x44, 0x53, 0x1b, 0x9f, 0x18, 0x4e, 0x54, 0x5d, 0x51, 0x44, 0x1f, 0x46, 0x48, 0x55, 0x44, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x45, 0x4e, 0x51, 0x4c, 0x1d, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x58, 0x4e, 0x54, 0x1f, 0x47, 0x40, 0x55, 0xc4, 0x53, 0x4e, 0x1f, 0x56, 0x51, 0x48, 0x53, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x9f, ], [0x52, 0x4e, 0x4d, 0x4d, 0x44, 0x53, 0x1f, 0x58, 0x4e, 0x54, 0x51, 0x52, 0x44, 0x4b, 0x45, 0x1b, 0x9f, 0x1c, 0xb, 0x5d, 0x4, 0x4d, 0x46, 0x4b, 0x44, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0xb, 0x48, 0x4a, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4c, 0x4e, 0x4e, 0x4d, 0x1f, 0x4e, 0x55, 0x44, 0xd1, 0x53, 0x47, 0x44, 0x1f, 0x43, 0x40, 0x58, 0x1f, 0x4c, 0x58, 0x1f, 0x46, 0x44, 0x4d, 0x48, 0x54, 0x52, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x41, 0x51, 0x40, 0x56, 0x4d, 0x1f, 0x40, 0x51, 0x44, 0x1f, 0x4b, 0x4e, 0x52, 0xd3, 0x4e, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x52, 0x44, 0x1f, 0x45, 0x4e, 0x4e, 0x4b, 0x52, 0x9f, 0x1c, 0x7, 0x40, 0x48, 0x4a, 0x54, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x8, 0x4d, 0x1f, 0x40, 0x1f, 0x47, 0x4e, 0x4b, 0x44, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x46, 0x51, 0x4e, 0x54, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x4b, 0x48, 0x55, 0x44, 0xc3, 0x40, 0x1f, 0x47, 0x4e, 0x41, 0x41, 0x48, 0x53, 0x1b, 0x1f, 0xd, 0x4e, 0x53, 0x1f, 0x40, 0x9f, 0x4d, 0x40, 0x52, 0x53, 0x58, 0x1d, 0x1f, 0x43, 0x48, 0x51, 0x53, 0x58, 0x1d, 0x1f, 0x56, 0x44, 0x53, 0x9f, 0x47, 0x4e, 0x4b, 0x44, 0x1d, 0x1f, 0x45, 0x48, 0x4b, 0x4b, 0x44, 0x43, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x44, 0x4d, 0x43, 0x52, 0x1f, 0x4e, 0x45, 0x1f, 0x56, 0x4e, 0x51, 0x4c, 0x52, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x40, 0x4d, 0x1f, 0x4e, 0x4e, 0x59, 0x58, 0x1f, 0x52, 0x4c, 0x44, 0x4b, 0x4b, 0x9d, 0x4d, 0x4e, 0x51, 0x1f, 0x58, 0x44, 0x53, 0x1f, 0x40, 0x1f, 0x43, 0x51, 0x58, 0x1d, 0x9f, ], [0x41, 0x40, 0x51, 0x44, 0x1d, 0x1f, 0x52, 0x40, 0x4d, 0x43, 0x58, 0x1f, 0x47, 0x4e, 0x4b, 0x44, 0x9f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x4d, 0x4e, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1f, 0x48, 0x4d, 0x1f, 0x48, 0xd3, 0x53, 0x4e, 0x1f, 0x52, 0x48, 0x53, 0x1f, 0x43, 0x4e, 0x56, 0x4d, 0x1f, 0x4e, 0x4d, 0x1f, 0x4e, 0x51, 0x9f, 0x53, 0x4e, 0x1f, 0x44, 0x40, 0x53, 0x1b, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x40, 0x9f, 0x47, 0x4e, 0x41, 0x41, 0x48, 0x53, 0x1c, 0x47, 0x4e, 0x4b, 0x44, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x4c, 0x44, 0x40, 0x4d, 0x52, 0x9f, 0x42, 0x4e, 0x4c, 0x45, 0x4e, 0x51, 0x53, 0x1b, 0x1f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, ]],
|
||||
[[0x5d, 0x6, 0x4e, 0x4e, 0x43, 0x1f, 0xc, 0x4e, 0x51, 0x4d, 0x48, 0x4d, 0x46, 0x1a, 0x5d, 0x9f, 0x52, 0x40, 0x48, 0x43, 0x1f, 0x1, 0x48, 0x4b, 0x41, 0x4e, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x47, 0xc4, 0x4c, 0x44, 0x40, 0x4d, 0x53, 0x1f, 0x48, 0x53, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x1f, 0x52, 0x54, 0x4d, 0x9f, 0x56, 0x40, 0x52, 0x1f, 0x52, 0x47, 0x48, 0x4d, 0x48, 0x4d, 0x46, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x46, 0x51, 0x40, 0x52, 0x52, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x55, 0x44, 0x51, 0xd8, 0x46, 0x51, 0x44, 0x44, 0x4d, 0x1b, 0x1f, 0x1, 0x54, 0x53, 0x1f, 0x6, 0x40, 0x4d, 0x43, 0x40, 0x4b, 0xc5, 0x4b, 0x4e, 0x4e, 0x4a, 0x44, 0x43, 0x1f, 0x40, 0x53, 0x1f, 0x47, 0x48, 0x4c, 0x1f, 0x45, 0x51, 0x4e, 0xcc, 0x54, 0x4d, 0x43, 0x44, 0x51, 0x1f, 0x4b, 0x4e, 0x4d, 0x46, 0x1f, 0x41, 0x54, 0x52, 0x47, 0x58, 0x9f, ], [0x44, 0x58, 0x44, 0x41, 0x51, 0x4e, 0x56, 0x52, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x9f, 0x52, 0x53, 0x54, 0x42, 0x4a, 0x1f, 0x4e, 0x54, 0x53, 0x1f, 0x45, 0x54, 0x51, 0x53, 0x47, 0x44, 0x51, 0x9f, 0x53, 0x47, 0x40, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x41, 0x51, 0x48, 0x4c, 0x1f, 0x4e, 0x45, 0x9f, 0x47, 0x48, 0x52, 0x1f, 0x52, 0x47, 0x40, 0x43, 0x58, 0x1f, 0x47, 0x40, 0x53, 0x1b, 0x9f, 0x5d, 0x16, 0x47, 0x40, 0x53, 0x1f, 0x43, 0x4e, 0x1f, 0x58, 0x4e, 0x54, 0x9f, 0x4c, 0x44, 0x40, 0x4d, 0x1e, 0x5d, 0x1f, 0x47, 0x44, 0x1f, 0x52, 0x40, 0x48, 0x43, 0x1b, 0x9f, 0x5d, 0x3, 0x4e, 0x1f, 0x58, 0x4e, 0x54, 0x1f, 0x56, 0x48, 0x52, 0x47, 0x1f, 0x4c, 0x44, 0x1f, 0x40, 0x9f, 0x46, 0x4e, 0x4e, 0x43, 0x1f, 0x4c, 0x4e, 0x51, 0x4d, 0x48, 0x4d, 0x46, 0x1d, 0x1f, 0x4e, 0x51, 0x9f, ], [0x4c, 0x44, 0x40, 0x4d, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x48, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x40, 0x9f, 0x46, 0x4e, 0x4e, 0x43, 0x1f, 0x4c, 0x4e, 0x51, 0x4d, 0x48, 0x4d, 0x46, 0x9f, 0x56, 0x47, 0x44, 0x53, 0x47, 0x44, 0x51, 0x1f, 0x8, 0x1f, 0x56, 0x40, 0x4d, 0x53, 0x1f, 0x48, 0x53, 0x9f, 0x4e, 0x51, 0x1f, 0x4d, 0x4e, 0x53, 0x1d, 0x1f, 0x4e, 0x51, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x9f, 0x58, 0x4e, 0x54, 0x1f, 0x45, 0x44, 0x44, 0x4b, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x1f, 0x53, 0x47, 0x48, 0xd2, 0x4c, 0x4e, 0x51, 0x4d, 0x48, 0x4d, 0x46, 0x1d, 0x1f, 0x4e, 0x51, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x9f, 0x48, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x40, 0x1f, 0x4c, 0x4e, 0x51, 0x4d, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0xce, 0x41, 0x44, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x1f, 0x4e, 0x4d, 0x1e, 0x5d, 0x1f, 0x5d, 0x0, 0x4b, 0x4b, 0x9f, ], [0x4e, 0x45, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x40, 0x53, 0x1f, 0x4e, 0x4d, 0x42, 0x44, 0x1d, 0x5d, 0x9f, 0x52, 0x40, 0x48, 0x43, 0x1f, 0x1, 0x48, 0x4b, 0x41, 0x4e, 0x1b, 0x9f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x5d, 0x6, 0x4e, 0x4e, 0x43, 0x1f, 0x4c, 0x4e, 0x51, 0x4d, 0x48, 0x4d, 0x46, 0x1a, 0x5d, 0x1f, 0x47, 0xc4, 0x52, 0x40, 0x48, 0x43, 0x1f, 0x40, 0x53, 0x1f, 0x4b, 0x40, 0x52, 0x53, 0x1b, 0x1f, 0x5d, 0x16, 0x44, 0x9f, 0x43, 0x4e, 0x4d, 0x5d, 0x53, 0x1f, 0x56, 0x40, 0x4d, 0x53, 0x1f, 0x40, 0x4d, 0x58, 0x9f, 0x40, 0x43, 0x55, 0x44, 0x4d, 0x53, 0x54, 0x51, 0x44, 0x52, 0x1f, 0x47, 0x44, 0x51, 0x44, 0x1d, 0x9f, 0x53, 0x47, 0x40, 0x4d, 0x4a, 0x1f, 0x58, 0x4e, 0x54, 0x1a, 0x1f, 0x18, 0x4e, 0x54, 0x9f, 0x4c, 0x48, 0x46, 0x47, 0x53, 0x1f, 0x53, 0x51, 0x58, 0x1f, 0x4e, 0x55, 0x44, 0x51, 0x1f, 0x13, 0x47, 0xc4, 0x7, 0x48, 0x4b, 0x4b, 0x1f, 0x4e, 0x51, 0x1f, 0x40, 0x42, 0x51, 0x4e, 0x52, 0x52, 0x1f, 0x13, 0x47, 0xc4, 0x16, 0x40, 0x53, 0x44, 0x51, 0x1b, 0x5d, 0x1f, 0x1, 0x58, 0x1f, 0x53, 0x47, 0x48, 0x52, 0x1f, 0x47, 0xc4, ], [0x4c, 0x44, 0x40, 0x4d, 0x53, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x42, 0x4e, 0x4d, 0x55, 0x44, 0x51, 0x52, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1f, 0x56, 0x40, 0x52, 0x9f, 0x40, 0x53, 0x1f, 0x40, 0x4d, 0x1f, 0x44, 0x4d, 0x43, 0x1b, 0x1f, 0x5d, 0x16, 0x47, 0x40, 0x53, 0x1f, 0xc0, 0x4b, 0x4e, 0x53, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x52, 0x1f, 0x58, 0x4e, 0x54, 0x9f, 0x43, 0x4e, 0x1f, 0x54, 0x52, 0x44, 0x1f, 0x6, 0x4e, 0x4e, 0x43, 0x9f, 0x4c, 0x4e, 0x51, 0x4d, 0x48, 0x4d, 0x46, 0x1f, 0x45, 0x4e, 0x51, 0x1a, 0x5d, 0x1f, 0x52, 0x40, 0x48, 0xc3, 0x6, 0x40, 0x4d, 0x43, 0x40, 0x4b, 0x45, 0x1b, 0x1f, 0x5d, 0xd, 0x4e, 0x56, 0x1f, 0x58, 0x4e, 0x54, 0x9f, 0x4c, 0x44, 0x40, 0x4d, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x58, 0x4e, 0x54, 0x1f, 0x56, 0x40, 0x4d, 0xd3, ], [0x53, 0x4e, 0x1f, 0x46, 0x44, 0x53, 0x1f, 0x51, 0x48, 0x43, 0x1f, 0x4e, 0x45, 0x1f, 0x4c, 0x44, 0x1d, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x4e, 0x4d, 0x5d, 0x53, 0x9f, 0x41, 0x44, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x1f, 0x53, 0x48, 0x4b, 0x4b, 0x1f, 0x8, 0x9f, 0x4c, 0x4e, 0x55, 0x44, 0x1f, 0x4e, 0x45, 0x45, 0x1b, 0x1b, 0x9f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x5d, 0x13, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x48, 0x52, 0x1f, 0x4d, 0x4e, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x9f, 0x4b, 0x48, 0x4a, 0x44, 0x1f, 0x4b, 0x4e, 0x4e, 0x4a, 0x48, 0x4d, 0x46, 0x1d, 0x1f, 0x48, 0x45, 0x9f, 0x58, 0x4e, 0x54, 0x1f, 0x56, 0x40, 0x4d, 0x53, 0x1f, 0x53, 0x4e, 0x1f, 0x45, 0x48, 0x4d, 0x43, 0x9f, 0x52, 0x4e, 0x4c, 0x44, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1b, 0x1f, 0x18, 0x4e, 0x54, 0x9f, 0x42, 0x44, 0x51, 0x53, 0x40, 0x48, 0x4d, 0x4b, 0x58, 0x1f, 0x54, 0x52, 0x54, 0x40, 0x4b, 0x4b, 0x58, 0x9f, 0x45, 0x48, 0x4d, 0x43, 0x1f, 0x52, 0x4e, 0x4c, 0x44, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1d, 0x1f, 0x48, 0xc5, 0x58, 0x4e, 0x54, 0x1f, 0x4b, 0x4e, 0x4e, 0x4a, 0x1d, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x48, 0x53, 0x9f, 0x48, 0x52, 0x1f, 0x4d, 0x4e, 0x53, 0x1f, 0x40, 0x4b, 0x56, 0x40, 0x58, 0x52, 0x9f, ], [0x50, 0x54, 0x48, 0x53, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x52, 0x4e, 0x4c, 0x44, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1f, 0x58, 0x4e, 0x54, 0x1f, 0x56, 0x44, 0x51, 0xc4, 0x40, 0x45, 0x53, 0x44, 0x51, 0x1b, 0x5d, 0x1f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x3, 0x51, 0x54, 0x4c, 0x4c, 0x44, 0x51, 0x1d, 0x1f, 0x41, 0x44, 0x40, 0x53, 0x1d, 0x1f, 0x40, 0x4d, 0xc3, 0x4f, 0x48, 0x4f, 0x44, 0x51, 0x1d, 0x1f, 0x41, 0x4b, 0x4e, 0x56, 0x1b, 0x9f, 0x7, 0x40, 0x51, 0x4f, 0x44, 0x51, 0x1d, 0x1f, 0x52, 0x53, 0x51, 0x48, 0x4a, 0x44, 0x1d, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x52, 0x4e, 0x4b, 0x43, 0x48, 0x44, 0x51, 0x1d, 0x1f, 0x46, 0x4e, 0x1b, 0x9f, 0x5, 0x51, 0x44, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x45, 0x4b, 0x40, 0x4c, 0x44, 0x1f, 0x40, 0x4d, 0xc3, 0x52, 0x44, 0x40, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x46, 0x51, 0x40, 0x52, 0x52, 0x44, 0x52, 0x1d, 0x9f, 0x13, 0x48, 0x4b, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x43, 0x40, 0x56, 0x4d, 0x48, 0x4d, 0x46, 0x9f, 0x11, 0x44, 0x43, 0x1f, 0x12, 0x53, 0x40, 0x51, 0x1f, 0x4f, 0x40, 0x52, 0x52, 0x44, 0x52, 0x1b, 0x9f, ], [0x1c, 0xc, 0x42, 0x2, 0x40, 0x45, 0x45, 0x51, 0x44, 0x58, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x13, 0x47, 0x44, 0x1f, 0x53, 0x44, 0x40, 0x51, 0x52, 0x1f, 0x8, 0x1f, 0x45, 0x44, 0x44, 0x4b, 0x9f, 0x53, 0x4e, 0x43, 0x40, 0x58, 0x1f, 0x8, 0x5d, 0x4b, 0x4b, 0x1f, 0x56, 0x40, 0x48, 0x53, 0x1f, 0x53, 0xce, 0x52, 0x47, 0x44, 0x43, 0x1f, 0x53, 0x4e, 0x4c, 0x4e, 0x51, 0x51, 0x4e, 0x56, 0x1b, 0x9f, 0x13, 0x47, 0x4e, 0x54, 0x46, 0x47, 0x1f, 0x8, 0x5d, 0x4b, 0x4b, 0x1f, 0x4d, 0x4e, 0x53, 0x9f, 0x52, 0x4b, 0x44, 0x44, 0x4f, 0x1f, 0x53, 0x47, 0x48, 0x52, 0x1f, 0x4d, 0x48, 0x46, 0x47, 0x53, 0x9f, 0xd, 0x4e, 0x51, 0x1f, 0x45, 0x48, 0x4d, 0x43, 0x1f, 0x52, 0x54, 0x51, 0x42, 0x44, 0x40, 0x52, 0x44, 0x9f, 0x45, 0x51, 0x4e, 0x4c, 0x1f, 0x52, 0x4e, 0x51, 0x51, 0x4e, 0x56, 0x1b, 0x1f, 0xc, 0x58, 0x9f, 0x44, 0x58, 0x44, 0x52, 0x1f, 0x4c, 0x54, 0x52, 0x53, 0x1f, 0x4a, 0x44, 0x44, 0x4f, 0x9f, ], [0x53, 0x47, 0x44, 0x48, 0x51, 0x1f, 0x52, 0x48, 0x46, 0x47, 0x53, 0x1b, 0x1f, 0x8, 0x9f, 0x43, 0x40, 0x51, 0x44, 0x1f, 0x4d, 0x4e, 0x53, 0x1f, 0x41, 0x44, 0x9f, 0x53, 0x44, 0x40, 0x51, 0x1c, 0x41, 0x4b, 0x48, 0x4d, 0x43, 0x44, 0x43, 0x1b, 0x1f, 0x8, 0x9f, 0x4c, 0x54, 0x52, 0x53, 0x1f, 0x41, 0x44, 0x1f, 0x45, 0x51, 0x44, 0x44, 0x1f, 0x53, 0x4e, 0x9f, 0x53, 0x40, 0x4b, 0x4a, 0x1f, 0xd, 0x4e, 0x53, 0x1f, 0x42, 0x47, 0x4e, 0x4a, 0x44, 0x43, 0x9f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x46, 0x51, 0x48, 0x44, 0x45, 0x1d, 0x9f, 0x42, 0x4b, 0x44, 0x40, 0x51, 0x1c, 0x4c, 0x48, 0x4d, 0x43, 0x44, 0x43, 0x1b, 0x1f, 0xc, 0x58, 0x9f, 0x4c, 0x4e, 0x54, 0x53, 0x47, 0x1f, 0x42, 0x40, 0x4d, 0x4d, 0x4e, 0x53, 0x9f, ], [0x41, 0x44, 0x53, 0x51, 0x40, 0x58, 0x1f, 0x13, 0x47, 0x44, 0x1f, 0x40, 0x4d, 0x46, 0x54, 0x48, 0x52, 0xc7, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x8, 0x1f, 0x4a, 0x4d, 0x4e, 0x56, 0x1b, 0x1f, 0x18, 0x44, 0x52, 0x1d, 0x9f, 0x8, 0x5d, 0x4b, 0x4b, 0x1f, 0x4a, 0x44, 0x44, 0x4f, 0x1f, 0x4c, 0x58, 0x1f, 0x53, 0x44, 0x40, 0x51, 0xd2, 0x53, 0x48, 0x4b, 0x1f, 0x4b, 0x40, 0x53, 0x44, 0x51, 0x1b, 0x1f, 0x1, 0x54, 0x53, 0x1f, 0x4c, 0x58, 0x9f, 0x46, 0x51, 0x48, 0x44, 0x45, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x4d, 0x44, 0x55, 0x44, 0x51, 0x9f, 0x46, 0x4e, 0x1b, 0x1f, 0x1c, 0xc, 0x42, 0x2, 0x40, 0x45, 0x45, 0x51, 0x44, 0x58, 0x1f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x16, 0x47, 0x4e, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x52, 0x1d, 0x1f, 0x2, 0x40, 0x4d, 0x1b, 0x9f, 0x16, 0x47, 0x4e, 0x1f, 0x53, 0x51, 0x48, 0x44, 0x52, 0x1d, 0x1f, 0x3, 0x4e, 0x44, 0x52, 0x1b, 0x9f, 0x16, 0x47, 0x4e, 0x1f, 0x4b, 0x4e, 0x55, 0x44, 0x52, 0x1d, 0x1f, 0xb, 0x48, 0x55, 0x44, 0x52, 0x1b, 0x9f, 0x1c, 0xc, 0x42, 0x2, 0x40, 0x45, 0x45, 0x51, 0x44, 0x58, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x13, 0x47, 0x44, 0x1f, 0x4b, 0x48, 0x53, 0x53, 0x4b, 0x44, 0x1f, 0x50, 0x54, 0x44, 0x44, 0x4d, 0x9f, 0x40, 0x4b, 0x4b, 0x1f, 0x46, 0x4e, 0x4b, 0x43, 0x44, 0x4d, 0x1f, 0x5, 0x4b, 0x44, 0x56, 0x9f, 0x47, 0x48, 0x52, 0x52, 0x48, 0x4d, 0x46, 0x1f, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x52, 0x44, 0x40, 0x1b, 0x1f, 0x13, 0x4e, 0x1f, 0x52, 0x53, 0x4e, 0x4f, 0x1f, 0x44, 0x40, 0x42, 0x47, 0x9f, 0x56, 0x40, 0x55, 0x44, 0x1f, 0x7, 0x44, 0x51, 0x1f, 0x42, 0x4b, 0x54, 0x53, 0x42, 0x47, 0x1f, 0x53, 0xce, 0x52, 0x40, 0x55, 0x44, 0x1f, 0x12, 0x47, 0x44, 0x1f, 0x55, 0x44, 0x4d, 0x53, 0x54, 0x51, 0x44, 0x43, 0x9f, 0x41, 0x51, 0x40, 0x55, 0x44, 0x4b, 0x58, 0x1b, 0x1f, 0x0, 0x52, 0x1f, 0x52, 0x47, 0x44, 0x9f, 0x40, 0x53, 0x53, 0x40, 0x42, 0x4a, 0x44, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x44, 0x40, 0x9f, ], [0x48, 0x4d, 0x1f, 0x51, 0x40, 0x46, 0x44, 0x1f, 0x0, 0x9f, 0x47, 0x4e, 0x4b, 0x43, 0x44, 0x51, 0x4c, 0x40, 0x4d, 0x1f, 0x42, 0x40, 0x4c, 0x44, 0x9f, 0x4d, 0x48, 0x46, 0x47, 0x1f, 0x0, 0x4b, 0x4e, 0x4d, 0x46, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x52, 0x40, 0x4d, 0x43, 0x1f, 0x5, 0x48, 0x52, 0x47, 0x4d, 0x44, 0x53, 0x1f, 0x48, 0x4d, 0x9f, 0x47, 0x40, 0x4d, 0x43, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x52, 0x40, 0x56, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x50, 0x54, 0x44, 0x44, 0x4d, 0x1f, 0x4c, 0x48, 0x43, 0x52, 0x4a, 0x58, 0x1b, 0x1f, 0x7, 0x44, 0x9f, 0x52, 0x53, 0x40, 0x51, 0x44, 0x43, 0x1f, 0x40, 0x53, 0x1f, 0x47, 0x44, 0x51, 0x1f, 0x48, 0x4d, 0x9f, 0x56, 0x4e, 0x4d, 0x43, 0x44, 0x51, 0x1f, 0x5, 0x4e, 0x51, 0x1f, 0x4e, 0x45, 0x53, 0x44, 0x4d, 0x9f, ], [0x47, 0x44, 0x5d, 0x43, 0x1f, 0x41, 0x44, 0x44, 0x4d, 0x1f, 0x53, 0x4e, 0x4b, 0x43, 0x9f, 0x13, 0x47, 0x40, 0x53, 0x1f, 0x52, 0x54, 0x42, 0x47, 0x1f, 0x40, 0x52, 0x1f, 0x52, 0x47, 0x44, 0x9f, 0x2, 0x4e, 0x54, 0x4b, 0x43, 0x1f, 0x4d, 0x44, 0x55, 0x44, 0x51, 0x1f, 0x41, 0x44, 0x1f, 0x16, 0x47, 0xce, 0x47, 0x4e, 0x55, 0x44, 0x51, 0x44, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x1d, 0x9f, 0x41, 0x51, 0x48, 0x46, 0x47, 0x53, 0x1f, 0x46, 0x4e, 0x4b, 0x43, 0x1b, 0x1f, 0x7, 0x44, 0x9f, 0x52, 0x40, 0x56, 0x1f, 0x47, 0x44, 0x51, 0x1f, 0x4f, 0x4b, 0x48, 0x46, 0x47, 0x53, 0x1f, 0x40, 0x4d, 0xc3, 0x50, 0x54, 0x48, 0x42, 0x4a, 0x4b, 0x58, 0x1f, 0x7, 0x44, 0x1f, 0x4b, 0x4e, 0x4e, 0x4a, 0x44, 0x43, 0x9f, 0x54, 0x4f, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x42, 0x4b, 0x48, 0x45, 0x45, 0x1f, 0x47, 0x44, 0x9f, ], [0x45, 0x40, 0x42, 0x44, 0x43, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x52, 0x40, 0x56, 0x1f, 0x40, 0x9f, 0x42, 0x40, 0x55, 0x44, 0x1f, 0x0, 0x41, 0x4e, 0x55, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x56, 0x40, 0x55, 0x44, 0x1f, 0x8, 0x4d, 0x1f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x47, 0x44, 0x51, 0x9f, 0x44, 0x46, 0x46, 0x52, 0x1f, 0x47, 0x44, 0x1f, 0x4f, 0x4b, 0x40, 0x42, 0x44, 0x43, 0x1b, 0x9f, 0x13, 0x47, 0x44, 0x1f, 0x4b, 0x48, 0x53, 0x53, 0x4b, 0x44, 0x1f, 0x50, 0x54, 0x44, 0x44, 0x4d, 0x9f, 0x40, 0x4b, 0x4b, 0x1f, 0x46, 0x4e, 0x4b, 0x43, 0x44, 0x4d, 0x1f, 0x14, 0x4f, 0x4e, 0x4d, 0x9f, 0x47, 0x48, 0x52, 0x1f, 0x52, 0x47, 0x4e, 0x54, 0x4b, 0x43, 0x44, 0x51, 0x1f, 0x52, 0x53, 0x4e, 0x4e, 0xc3, 0x7, 0x44, 0x51, 0x1f, 0x44, 0x58, 0x44, 0x52, 0x1f, 0x40, 0x4b, 0x4b, 0x1f, 0x41, 0x4b, 0x54, 0x44, 0x9f, ], [0x6, 0x4b, 0x4e, 0x56, 0x44, 0x43, 0x1f, 0x4e, 0x45, 0x1f, 0x47, 0x44, 0x51, 0x1f, 0x53, 0x51, 0x54, 0xc4, 0x14, 0x4d, 0x43, 0x58, 0x48, 0x4d, 0x46, 0x1f, 0x46, 0x51, 0x40, 0x53, 0x48, 0x53, 0x54, 0x43, 0x44, 0x9b, 0x1c, 0xc, 0x42, 0x2, 0x40, 0x45, 0x45, 0x51, 0x44, 0x58, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x7, 0x40, 0x51, 0x4f, 0x44, 0x51, 0x1d, 0x1f, 0x53, 0x51, 0x44, 0x40, 0x53, 0x1f, 0x58, 0x4e, 0x54, 0xd1, 0x56, 0x4e, 0x51, 0x43, 0x52, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x42, 0x40, 0x51, 0x44, 0x9f, 0x5, 0x4e, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x4c, 0x40, 0x58, 0x1f, 0x42, 0x40, 0x54, 0x52, 0xc4, 0x49, 0x4e, 0x58, 0x1f, 0x4e, 0x51, 0x1f, 0x43, 0x44, 0x52, 0x4f, 0x40, 0x48, 0x51, 0x9f, 0x12, 0x48, 0x4d, 0x46, 0x1f, 0x58, 0x4e, 0x54, 0x51, 0x1f, 0x52, 0x4e, 0x4d, 0x46, 0x52, 0x1f, 0x4e, 0xc5, 0x47, 0x44, 0x40, 0x4b, 0x53, 0x47, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x4b, 0x4e, 0x55, 0x44, 0x1f, 0xe, 0xc5, 0x43, 0x51, 0x40, 0x46, 0x4e, 0x4d, 0x52, 0x1f, 0x45, 0x4b, 0x40, 0x4c, 0x48, 0x4d, 0x46, 0x9f, 0x45, 0x51, 0x4e, 0x4c, 0x1f, 0x40, 0x41, 0x4e, 0x55, 0x44, 0x1b, 0x9f, ], [0x1c, 0xc, 0x42, 0x2, 0x40, 0x45, 0x45, 0x51, 0x44, 0x58, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x13, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x4e, 0x4d, 0x4b, 0x58, 0x1f, 0x4e, 0x4d, 0xc4, 0x42, 0x40, 0x53, 0x42, 0x47, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x56, 0x40, 0xd2, 0x2, 0x40, 0x53, 0x42, 0x47, 0x1c, 0x24, 0x24, 0x1d, 0x1f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x9f, 0x52, 0x4f, 0x44, 0x42, 0x48, 0x45, 0x48, 0x44, 0x43, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x40, 0x9f, 0x42, 0x4e, 0x4d, 0x42, 0x44, 0x51, 0x4d, 0x1f, 0x45, 0x4e, 0x51, 0x1f, 0x4e, 0x4d, 0x44, 0x5d, 0x52, 0x9f, 0x52, 0x40, 0x45, 0x44, 0x53, 0x58, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x45, 0x40, 0x42, 0xc4, 0x4e, 0x45, 0x1f, 0x43, 0x40, 0x4d, 0x46, 0x44, 0x51, 0x52, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x9f, 0x56, 0x44, 0x51, 0x44, 0x1f, 0x51, 0x44, 0x40, 0x4b, 0x1f, 0x40, 0x4d, 0x43, 0x9f, ], [0x48, 0x4c, 0x4c, 0x44, 0x43, 0x48, 0x40, 0x53, 0x44, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4f, 0x51, 0x4e, 0x42, 0x44, 0x52, 0x52, 0x1f, 0x4e, 0x45, 0x1f, 0x40, 0x9f, 0x51, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x40, 0x4b, 0x1f, 0x4c, 0x48, 0x4d, 0x43, 0x1b, 0x1f, 0xe, 0x51, 0xd1, 0x56, 0x40, 0x52, 0x1f, 0x42, 0x51, 0x40, 0x59, 0x58, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x42, 0x4e, 0x54, 0x4b, 0x43, 0x1f, 0x41, 0x44, 0x1f, 0x46, 0x51, 0x4e, 0x54, 0x4d, 0x43, 0x44, 0x43, 0x9b, 0x0, 0x4b, 0x4b, 0x1f, 0x47, 0x44, 0x1f, 0x47, 0x40, 0x43, 0x1f, 0x53, 0x4e, 0x1f, 0x43, 0x4e, 0x9f, 0x56, 0x40, 0x52, 0x1f, 0x40, 0x52, 0x4a, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x40, 0x52, 0x9f, 0x52, 0x4e, 0x4e, 0x4d, 0x1f, 0x40, 0x52, 0x1f, 0x47, 0x44, 0x1f, 0x43, 0x48, 0x43, 0x1d, 0x1f, 0x47, 0xc4, ], [0x56, 0x4e, 0x54, 0x4b, 0x43, 0x1f, 0x4d, 0x4e, 0x1f, 0x4b, 0x4e, 0x4d, 0x46, 0x44, 0x51, 0x1f, 0x41, 0xc4, 0x42, 0x51, 0x40, 0x59, 0x58, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x56, 0x4e, 0x54, 0x4b, 0x43, 0x9f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x53, 0x4e, 0x1f, 0x45, 0x4b, 0x58, 0x1f, 0x4c, 0x4e, 0x51, 0x44, 0x9f, 0x4c, 0x48, 0x52, 0x52, 0x48, 0x4e, 0x4d, 0x52, 0x1b, 0x1f, 0xe, 0x51, 0x51, 0x9f, 0x56, 0x4e, 0x54, 0x4b, 0x43, 0x1f, 0x41, 0x44, 0x1f, 0x42, 0x51, 0x40, 0x59, 0x58, 0x1f, 0x53, 0x4e, 0x9f, 0x45, 0x4b, 0x58, 0x1f, 0x4c, 0x4e, 0x51, 0x44, 0x1f, 0x4c, 0x48, 0x52, 0x52, 0x48, 0x4e, 0x4d, 0x52, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x52, 0x40, 0x4d, 0x44, 0x1f, 0x48, 0x45, 0x1f, 0x47, 0x44, 0x9f, 0x43, 0x48, 0x43, 0x4d, 0x5d, 0x53, 0x1d, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x48, 0x45, 0x1f, 0x47, 0x44, 0x9f, ], [0x56, 0x40, 0x52, 0x1f, 0x52, 0x40, 0x4d, 0x44, 0x1f, 0x47, 0x44, 0x1f, 0x47, 0x40, 0x43, 0x1f, 0x53, 0xce, 0x45, 0x4b, 0x58, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1b, 0x1f, 0x8, 0x45, 0x1f, 0x47, 0x44, 0x9f, 0x45, 0x4b, 0x44, 0x56, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x47, 0x44, 0x1f, 0x56, 0x40, 0x52, 0x9f, 0x42, 0x51, 0x40, 0x59, 0x58, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x43, 0x48, 0x43, 0x4d, 0x5d, 0x53, 0x9f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x53, 0x4e, 0x1d, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x48, 0x45, 0x1f, 0x47, 0xc4, 0x43, 0x48, 0x43, 0x4d, 0x5d, 0x53, 0x1f, 0x56, 0x40, 0x4d, 0x53, 0x1f, 0x53, 0x4e, 0x1f, 0x47, 0x44, 0x9f, 0x56, 0x40, 0x52, 0x1f, 0x52, 0x40, 0x4d, 0x44, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x47, 0x40, 0x43, 0x9f, 0x53, 0x4e, 0x1b, 0x1f, 0x1c, 0x7, 0x44, 0x4b, 0x4b, 0x44, 0x51, 0x1f, 0x9f, ]],
|
||||
[[0x5d, 0x13, 0x47, 0x44, 0x58, 0x5d, 0x51, 0x44, 0x1f, 0x53, 0x51, 0x58, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0xce, 0x4a, 0x48, 0x4b, 0x4b, 0x1f, 0x4c, 0x44, 0x1d, 0x5d, 0x9f, 0x18, 0x4e, 0x52, 0x52, 0x40, 0x51, 0x48, 0x40, 0x4d, 0x1f, 0x53, 0x4e, 0x4b, 0x43, 0x1f, 0x47, 0x48, 0xcc, 0x42, 0x40, 0x4b, 0x4c, 0x4b, 0x58, 0x1b, 0x1f, 0x5d, 0xd, 0x4e, 0x1f, 0x4e, 0x4d, 0x44, 0x5d, 0x52, 0x9f, 0x53, 0x51, 0x58, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x4e, 0x1f, 0x4a, 0x48, 0x4b, 0x4b, 0x9f, 0x58, 0x4e, 0x54, 0x1d, 0x5d, 0x1f, 0x2, 0x4b, 0x44, 0x55, 0x48, 0x4d, 0x46, 0x44, 0x51, 0x9f, 0x42, 0x51, 0x48, 0x44, 0x43, 0x1b, 0x1f, 0x5d, 0x13, 0x47, 0x44, 0x4d, 0x1f, 0x56, 0x47, 0x58, 0x9f, 0x40, 0x51, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x52, 0x47, 0x4e, 0x4e, 0x53, 0x48, 0x4d, 0x46, 0x9f, ], [0x40, 0x53, 0x1f, 0x4c, 0x44, 0x1e, 0x5d, 0x1f, 0x18, 0x4e, 0x52, 0x52, 0x40, 0x51, 0x48, 0x40, 0x4d, 0x9f, 0x40, 0x52, 0x4a, 0x44, 0x43, 0x1b, 0x1f, 0x5d, 0x13, 0x47, 0x44, 0x58, 0x5d, 0x51, 0x44, 0x9f, 0x52, 0x47, 0x4e, 0x4e, 0x53, 0x48, 0x4d, 0x46, 0x1f, 0x40, 0x53, 0x9f, 0x44, 0x55, 0x44, 0x51, 0x58, 0x4e, 0x4d, 0x44, 0x1d, 0x5d, 0x9f, 0x2, 0x4b, 0x44, 0x55, 0x48, 0x4d, 0x46, 0x44, 0x51, 0x9f, 0x40, 0x4d, 0x52, 0x56, 0x44, 0x51, 0x44, 0x43, 0x1b, 0x1f, 0x5d, 0x13, 0x47, 0x44, 0x58, 0x5d, 0x51, 0xc4, 0x53, 0x51, 0x58, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x4e, 0x1f, 0x4a, 0x48, 0x4b, 0x4b, 0x9f, 0x44, 0x55, 0x44, 0x51, 0x58, 0x4e, 0x4d, 0x44, 0x1b, 0x5d, 0x1f, 0x0, 0x4d, 0x43, 0x9f, ], [0x56, 0x47, 0x40, 0x53, 0x1f, 0x43, 0x48, 0x45, 0x45, 0x44, 0x51, 0x44, 0x4d, 0x42, 0x44, 0x9f, 0x43, 0x4e, 0x44, 0x52, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x4c, 0x40, 0x4a, 0x44, 0x1e, 0x9f, 0x1c, 0x7, 0x44, 0x4b, 0x4b, 0x44, 0x51, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x18, 0x4e, 0x54, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x41, 0x51, 0x40, 0x48, 0x4d, 0x52, 0x1f, 0x48, 0xcd, 0x58, 0x4e, 0x54, 0x51, 0x1f, 0x47, 0x44, 0x40, 0x43, 0x1b, 0x1f, 0x18, 0x4e, 0x54, 0x9f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x45, 0x44, 0x44, 0x53, 0x1f, 0x48, 0x4d, 0x1f, 0x58, 0x4e, 0x54, 0x51, 0x9f, 0x52, 0x47, 0x4e, 0x44, 0x52, 0x1b, 0x1f, 0x18, 0x4e, 0x54, 0x1f, 0x42, 0x40, 0x4d, 0x9f, 0x52, 0x53, 0x44, 0x44, 0x51, 0x1f, 0x58, 0x4e, 0x54, 0x51, 0x52, 0x44, 0x4b, 0x45, 0x1f, 0x40, 0x4d, 0xd8, 0x43, 0x48, 0x51, 0x44, 0x42, 0x53, 0x48, 0x4e, 0x4d, 0x1f, 0x58, 0x4e, 0x54, 0x9f, 0x42, 0x47, 0x4e, 0x4e, 0x52, 0x44, 0x1b, 0x1f, 0x18, 0x4e, 0x54, 0x5d, 0x51, 0x44, 0x1f, 0x4e, 0x4d, 0x9f, 0x58, 0x4e, 0x54, 0x51, 0x1f, 0x4e, 0x56, 0x4d, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x58, 0x4e, 0x54, 0x9f, ], [0x4a, 0x4d, 0x4e, 0x56, 0x1f, 0x56, 0x47, 0x40, 0x53, 0x1f, 0x58, 0x4e, 0x54, 0x9f, 0x4a, 0x4d, 0x4e, 0x56, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x18, 0xe, 0x14, 0x1f, 0x40, 0x51, 0x44, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4e, 0x4d, 0x44, 0x1f, 0x56, 0x47, 0x4e, 0x5d, 0x4b, 0x4b, 0x9f, 0x43, 0x44, 0x42, 0x48, 0x43, 0x44, 0x1f, 0x56, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x53, 0x4e, 0x9f, 0x46, 0x4e, 0x1b, 0x1b, 0x1b, 0x1f, 0x1c, 0x12, 0x54, 0x44, 0x52, 0x52, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x16, 0x47, 0x44, 0x4d, 0x1f, 0x58, 0x4e, 0x54, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x9f, 0x44, 0x4b, 0x48, 0x4c, 0x48, 0x4d, 0x40, 0x53, 0x44, 0x43, 0x1f, 0x40, 0x4b, 0x4b, 0x9f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x48, 0x52, 0x9f, 0x48, 0x4c, 0x4f, 0x4e, 0x52, 0x52, 0x48, 0x41, 0x4b, 0x44, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x4d, 0x9f, 0x56, 0x47, 0x40, 0x53, 0x44, 0x55, 0x44, 0x51, 0x1f, 0x51, 0x44, 0x4c, 0x40, 0x48, 0x4d, 0x52, 0x1d, 0x9f, 0x47, 0x4e, 0x56, 0x44, 0x55, 0x44, 0x51, 0x9f, 0x48, 0x4c, 0x4f, 0x51, 0x4e, 0x41, 0x40, 0x41, 0x4b, 0x44, 0x1d, 0x1f, 0x4c, 0x54, 0x52, 0x53, 0x9f, 0x41, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x53, 0x51, 0x54, 0x53, 0x47, 0x1b, 0x9f, ], [0x1c, 0x3, 0x4e, 0x58, 0x4b, 0x44, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x5d, 0xc, 0x58, 0x1f, 0x4c, 0x48, 0x4d, 0x43, 0x1d, 0x5d, 0x1f, 0x47, 0x44, 0x9f, 0x52, 0x40, 0x48, 0x43, 0x1d, 0x1f, 0x5d, 0x51, 0x44, 0x41, 0x44, 0x4b, 0x52, 0x1f, 0x40, 0x53, 0x9f, 0x52, 0x53, 0x40, 0x46, 0x4d, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1b, 0x1f, 0x6, 0x48, 0x55, 0x44, 0x9f, 0x4c, 0x44, 0x1f, 0x4f, 0x51, 0x4e, 0x41, 0x4b, 0x44, 0x4c, 0x52, 0x1d, 0x1f, 0x46, 0x48, 0x55, 0x44, 0x9f, 0x4c, 0x44, 0x1f, 0x56, 0x4e, 0x51, 0x4a, 0x1d, 0x1f, 0x46, 0x48, 0x55, 0x44, 0x1f, 0x4c, 0x44, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4c, 0x4e, 0x52, 0x53, 0x1f, 0x40, 0x41, 0x52, 0x53, 0x51, 0x54, 0x52, 0x44, 0x9f, 0x42, 0x51, 0x58, 0x4f, 0x53, 0x4e, 0x46, 0x51, 0x40, 0x4c, 0x1f, 0x4e, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4c, 0x4e, 0x52, 0x53, 0x1f, 0x48, 0x4d, 0x53, 0x51, 0x48, 0x42, 0x40, 0x53, 0x44, 0x9f, ], [0x40, 0x4d, 0x40, 0x4b, 0x58, 0x52, 0x48, 0x52, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x8, 0x1f, 0x40, 0xcc, 0x48, 0x4d, 0x1f, 0x4c, 0x58, 0x1f, 0x4e, 0x56, 0x4d, 0x1f, 0x4f, 0x51, 0x4e, 0x4f, 0x44, 0x51, 0x9f, 0x40, 0x53, 0x4c, 0x4e, 0x52, 0x4f, 0x47, 0x44, 0x51, 0x44, 0x1b, 0x1f, 0x8, 0x1f, 0x42, 0x40, 0x4d, 0x9f, 0x43, 0x48, 0x52, 0x4f, 0x44, 0x4d, 0x52, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x4d, 0x1f, 0x56, 0x48, 0x53, 0xc7, 0x40, 0x51, 0x53, 0x48, 0x45, 0x48, 0x42, 0x48, 0x40, 0x4b, 0x9f, 0x52, 0x53, 0x48, 0x4c, 0x54, 0x4b, 0x40, 0x4d, 0x53, 0x52, 0x1b, 0x1f, 0x1, 0x54, 0x53, 0x1f, 0x8, 0x9f, 0x40, 0x41, 0x47, 0x4e, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x43, 0x54, 0x4b, 0x4b, 0x9f, 0x51, 0x4e, 0x54, 0x53, 0x48, 0x4d, 0x44, 0x1f, 0x4e, 0x45, 0x9f, ], [0x44, 0x57, 0x48, 0x52, 0x53, 0x44, 0x4d, 0x42, 0x44, 0x1b, 0x1f, 0x8, 0x1f, 0x42, 0x51, 0x40, 0x55, 0xc4, 0x45, 0x4e, 0x51, 0x1f, 0x4c, 0x44, 0x4d, 0x53, 0x40, 0x4b, 0x9f, 0x44, 0x57, 0x40, 0x4b, 0x53, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1b, 0x1f, 0x13, 0x47, 0x40, 0x53, 0x9f, 0x48, 0x52, 0x1f, 0x56, 0x47, 0x58, 0x1f, 0x8, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x9f, 0x42, 0x47, 0x4e, 0x52, 0x44, 0x4d, 0x1f, 0x4c, 0x58, 0x1f, 0x4e, 0x56, 0x4d, 0x9f, 0x4f, 0x40, 0x51, 0x53, 0x48, 0x42, 0x54, 0x4b, 0x40, 0x51, 0x9f, 0x4f, 0x51, 0x4e, 0x45, 0x44, 0x52, 0x52, 0x48, 0x4e, 0x4d, 0x1d, 0x1f, 0x4e, 0x51, 0x9f, 0x51, 0x40, 0x53, 0x47, 0x44, 0x51, 0x1f, 0x42, 0x51, 0x44, 0x40, 0x53, 0x44, 0x43, 0x1f, 0x48, 0x53, 0x9d, ], [0x45, 0x4e, 0x51, 0x1f, 0x8, 0x1f, 0x40, 0x4c, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4e, 0x4d, 0x4b, 0x58, 0x9f, 0x4e, 0x4d, 0x44, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x56, 0x4e, 0x51, 0x4b, 0x43, 0x1b, 0xdd, 0x1c, 0x3, 0x4e, 0x58, 0x4b, 0x44, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0xb, 0x48, 0x45, 0x44, 0x1f, 0x48, 0x52, 0x1f, 0x48, 0x4d, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x44, 0x4b, 0xd8, 0x52, 0x53, 0x51, 0x40, 0x4d, 0x46, 0x44, 0x51, 0x1f, 0x53, 0x47, 0x40, 0x4d, 0x9f, 0x40, 0x4d, 0x58, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x53, 0x47, 0xc4, 0x4c, 0x48, 0x4d, 0x43, 0x1f, 0x4e, 0x45, 0x1f, 0x4c, 0x40, 0x4d, 0x1f, 0x42, 0x4e, 0x54, 0x4b, 0x43, 0x9f, 0x48, 0x4d, 0x55, 0x44, 0x4d, 0x53, 0x1b, 0x1f, 0x16, 0x44, 0x1f, 0x56, 0x4e, 0x54, 0x4b, 0x43, 0x9f, 0x4d, 0x4e, 0x53, 0x1f, 0x43, 0x40, 0x51, 0x44, 0x1f, 0x53, 0x4e, 0x9f, 0x42, 0x4e, 0x4d, 0x42, 0x44, 0x48, 0x55, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x52, 0x1f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x40, 0x51, 0x44, 0x9f, ], [0x51, 0x44, 0x40, 0x4b, 0x4b, 0x58, 0x1f, 0x4c, 0x44, 0x51, 0x44, 0x9f, 0x42, 0x4e, 0x4c, 0x4c, 0x4e, 0x4d, 0x4f, 0x4b, 0x40, 0x42, 0x44, 0x52, 0x1f, 0x4e, 0x45, 0x9f, 0x44, 0x57, 0x48, 0x52, 0x53, 0x44, 0x4d, 0x42, 0x44, 0x1b, 0x1f, 0x8, 0x45, 0x1f, 0x56, 0x44, 0x9f, 0x42, 0x4e, 0x54, 0x4b, 0x43, 0x1f, 0x45, 0x4b, 0x58, 0x1f, 0x4e, 0x54, 0x53, 0x1f, 0x4e, 0x45, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x56, 0x48, 0x4d, 0x43, 0x4e, 0x56, 0x1f, 0x47, 0x40, 0x4d, 0x43, 0x9f, 0x48, 0x4d, 0x1f, 0x47, 0x40, 0x4d, 0x43, 0x1d, 0x1f, 0x47, 0x4e, 0x55, 0x44, 0x51, 0x9f, 0x4e, 0x55, 0x44, 0x51, 0x1f, 0x53, 0x47, 0x48, 0x52, 0x1f, 0x46, 0x51, 0x44, 0x40, 0x53, 0x9f, 0x42, 0x48, 0x53, 0x58, 0x1d, 0x1f, 0x46, 0x44, 0x4d, 0x53, 0x4b, 0x58, 0x9f, ], [0x51, 0x44, 0x4c, 0x4e, 0x55, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x51, 0x4e, 0x4e, 0x45, 0x52, 0x1d, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x4f, 0x44, 0x44, 0x4f, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0xd3, 0x53, 0x47, 0x44, 0x1f, 0x50, 0x54, 0x44, 0x44, 0x51, 0x1f, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x52, 0x9f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x40, 0x51, 0x44, 0x1f, 0x46, 0x4e, 0x48, 0x4d, 0x46, 0x9f, 0x4e, 0x4d, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x53, 0x51, 0x40, 0x4d, 0x46, 0x44, 0x9f, 0x42, 0x4e, 0x48, 0x4d, 0x42, 0x48, 0x43, 0x44, 0x4d, 0x42, 0x44, 0x52, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4f, 0x4b, 0x40, 0x4d, 0x4d, 0x48, 0x4d, 0x46, 0x52, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x42, 0x51, 0x4e, 0x52, 0x52, 0x1c, 0x4f, 0x54, 0x51, 0x4f, 0x4e, 0x52, 0x44, 0x52, 0x1d, 0x9f, ], [0x53, 0x47, 0x44, 0x1f, 0x56, 0x4e, 0x4d, 0x43, 0x44, 0x51, 0x45, 0x54, 0x4b, 0x9f, 0x42, 0x47, 0x40, 0x48, 0x4d, 0x52, 0x1f, 0x4e, 0x45, 0x1f, 0x44, 0x55, 0x44, 0x4d, 0x53, 0x52, 0x1d, 0x9f, 0x56, 0x4e, 0x51, 0x4a, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x9f, 0x46, 0x44, 0x4d, 0x44, 0x51, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x52, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x4b, 0x44, 0x40, 0x43, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x4e, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4c, 0x4e, 0x52, 0x53, 0x1f, 0x4e, 0x54, 0x53, 0x51, 0x44, 0x9f, 0x51, 0x44, 0x52, 0x54, 0x4b, 0x53, 0x52, 0x1d, 0x1f, 0x48, 0x53, 0x1f, 0x56, 0x4e, 0x54, 0x4b, 0x43, 0x9f, 0x4c, 0x40, 0x4a, 0x44, 0x1f, 0x40, 0x4b, 0x4b, 0x1f, 0x45, 0x48, 0x42, 0x53, 0x48, 0x4e, 0x4d, 0x9f, ], [0x56, 0x48, 0x53, 0x47, 0x1f, 0x48, 0x53, 0x52, 0x9f, 0x42, 0x4e, 0x4d, 0x55, 0x44, 0x4d, 0x53, 0x48, 0x4e, 0x4d, 0x40, 0x4b, 0x48, 0x53, 0x48, 0x44, 0x52, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x45, 0x4e, 0x51, 0x44, 0x52, 0x44, 0x44, 0x4d, 0x9f, 0x42, 0x4e, 0x4d, 0x42, 0x4b, 0x54, 0x52, 0x48, 0x4e, 0x4d, 0x52, 0x1f, 0x4c, 0x4e, 0x52, 0x53, 0x9f, 0x52, 0x53, 0x40, 0x4b, 0x44, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x54, 0x4d, 0x4f, 0x51, 0x4e, 0x45, 0x48, 0x53, 0x40, 0x41, 0x4b, 0x44, 0x1b, 0x9f, 0x1c, 0x3, 0x4e, 0x58, 0x4b, 0x44, 0x1f, 0x9f, 0x9f, ]],
|
||||
[[0x13, 0x47, 0x44, 0x1f, 0x52, 0x53, 0x4e, 0x51, 0x58, 0x1f, 0x52, 0x4e, 0x1f, 0x45, 0x40, 0x51, 0x1b, 0x9f, 0x8, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x41, 0x44, 0x46, 0x48, 0x4d, 0x4d, 0x48, 0x4d, 0x46, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x14, 0x4d, 0x48, 0x55, 0x44, 0x51, 0x52, 0x44, 0x1f, 0x56, 0x40, 0x52, 0x9f, 0x42, 0x51, 0x44, 0x40, 0x53, 0x44, 0x43, 0x1b, 0x1f, 0x13, 0x47, 0x48, 0x52, 0x1f, 0x47, 0x40, 0x52, 0x9f, 0x4c, 0x40, 0x43, 0x44, 0x1f, 0x40, 0x1f, 0x4b, 0x4e, 0x53, 0x1f, 0x4e, 0x45, 0x9f, 0x4f, 0x44, 0x4e, 0x4f, 0x4b, 0x44, 0x1f, 0x55, 0x44, 0x51, 0x58, 0x1f, 0x40, 0x4d, 0x46, 0x51, 0x58, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x41, 0x44, 0x44, 0x4d, 0x1f, 0x56, 0x48, 0x43, 0x44, 0x4b, 0x58, 0x9f, 0x51, 0x44, 0x46, 0x40, 0x51, 0x43, 0x44, 0x43, 0x1f, 0x40, 0x52, 0x1f, 0x40, 0x1f, 0x41, 0x40, 0x43, 0x9f, ], [0x4c, 0x4e, 0x55, 0x44, 0x1b, 0x1f, 0x1c, 0x0, 0x43, 0x40, 0x4c, 0x52, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x5, 0x4e, 0x51, 0x1f, 0x48, 0x4d, 0x52, 0x53, 0x40, 0x4d, 0x42, 0x44, 0x1d, 0x1f, 0x4e, 0x4d, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4f, 0x4b, 0x40, 0x4d, 0x44, 0x53, 0x1f, 0x4, 0x40, 0x51, 0x53, 0x47, 0x1d, 0x9f, 0x4c, 0x40, 0x4d, 0x1f, 0x47, 0x40, 0x43, 0x1f, 0x40, 0x4b, 0x56, 0x40, 0x58, 0x52, 0x9f, 0x40, 0x52, 0x52, 0x54, 0x4c, 0x44, 0x43, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x47, 0x44, 0x9f, 0x56, 0x40, 0x52, 0x1f, 0x4c, 0x4e, 0x51, 0x44, 0x9f, 0x48, 0x4d, 0x53, 0x44, 0x4b, 0x4b, 0x48, 0x46, 0x44, 0x4d, 0x53, 0x1f, 0x53, 0x47, 0x40, 0x4d, 0x9f, 0x43, 0x4e, 0x4b, 0x4f, 0x47, 0x48, 0x4d, 0x52, 0x1f, 0x41, 0x44, 0x42, 0x40, 0x54, 0x52, 0x44, 0x9f, 0x47, 0x44, 0x1f, 0x47, 0x40, 0x43, 0x1f, 0x40, 0x42, 0x47, 0x48, 0x44, 0x55, 0x44, 0x43, 0x1f, 0x52, 0xce, ], [0x4c, 0x54, 0x42, 0x47, 0x1c, 0x53, 0x47, 0x44, 0x1f, 0x56, 0x47, 0x44, 0x44, 0x4b, 0x1d, 0x9f, 0xd, 0x44, 0x56, 0x1f, 0x18, 0x4e, 0x51, 0x4a, 0x1d, 0x1f, 0x56, 0x40, 0x51, 0x52, 0x1f, 0x40, 0x4d, 0xc3, 0x52, 0x4e, 0x1f, 0x4e, 0x4d, 0x1c, 0x56, 0x47, 0x48, 0x4b, 0x52, 0x53, 0x1f, 0x40, 0x4b, 0x4b, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x43, 0x4e, 0x4b, 0x4f, 0x47, 0x48, 0x4d, 0x52, 0x1f, 0x47, 0x40, 0x43, 0x9f, 0x44, 0x55, 0x44, 0x51, 0x1f, 0x43, 0x4e, 0x4d, 0x44, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x4c, 0x54, 0x42, 0xca, 0x40, 0x41, 0x4e, 0x54, 0x53, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x56, 0x40, 0x53, 0x44, 0xd1, 0x47, 0x40, 0x55, 0x48, 0x4d, 0x46, 0x1f, 0x40, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x9f, 0x53, 0x48, 0x4c, 0x44, 0x1b, 0x1f, 0x1, 0x54, 0x53, 0x9f, ], [0x42, 0x4e, 0x4d, 0x55, 0x44, 0x51, 0x52, 0x44, 0x4b, 0x58, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x43, 0x4e, 0x4b, 0x4f, 0x47, 0x48, 0x4d, 0x52, 0x1f, 0x47, 0x40, 0x43, 0x9f, 0x40, 0x4b, 0x56, 0x40, 0x58, 0x52, 0x1f, 0x41, 0x44, 0x4b, 0x48, 0x44, 0x55, 0x44, 0x43, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x1f, 0x45, 0x40, 0xd1, 0x4c, 0x4e, 0x51, 0x44, 0x1f, 0x48, 0x4d, 0x53, 0x44, 0x4b, 0x4b, 0x48, 0x46, 0x44, 0x4d, 0x53, 0x9f, 0x53, 0x47, 0x40, 0x4d, 0x1f, 0x4c, 0x40, 0x4d, 0x1b, 0x45, 0x4e, 0x51, 0x9f, 0x4f, 0x51, 0x44, 0x42, 0x48, 0x52, 0x44, 0x4b, 0x58, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x40, 0x4c, 0xc4, 0x51, 0x44, 0x40, 0x52, 0x4e, 0x4d, 0x52, 0x1b, 0x1f, 0x1c, 0x0, 0x43, 0x40, 0x4c, 0x52, 0x1f, 0x9f, ]],
|
||||
[[0x8, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x4a, 0x4d, 0x4e, 0x56, 0x4d, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x9f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x40, 0x51, 0x44, 0x1f, 0x40, 0x4d, 0x9f, 0x48, 0x4d, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x44, 0x1f, 0x4d, 0x54, 0x4c, 0x41, 0x44, 0x51, 0x1f, 0x4e, 0xc5, 0x56, 0x4e, 0x51, 0x4b, 0x43, 0x52, 0x1d, 0x1f, 0x52, 0x48, 0x4c, 0x4f, 0x4b, 0x58, 0x9f, 0x41, 0x44, 0x42, 0x40, 0x54, 0x52, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x48, 0x52, 0x9f, 0x40, 0x4d, 0x1f, 0x48, 0x4d, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x44, 0x1f, 0x40, 0x4c, 0x4e, 0x54, 0x4d, 0xd3, 0x4e, 0x45, 0x1f, 0x52, 0x4f, 0x40, 0x42, 0x44, 0x1f, 0x45, 0x4e, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x9f, 0x53, 0x4e, 0x1f, 0x41, 0x44, 0x1f, 0x48, 0x4d, 0x1b, 0x1f, 0x7, 0x4e, 0x56, 0x44, 0x55, 0x44, 0x51, 0x9d, ], [0x4d, 0x4e, 0x53, 0x1f, 0x44, 0x55, 0x44, 0x51, 0x58, 0x1f, 0x4e, 0x4d, 0x44, 0x1f, 0x4e, 0x45, 0x9f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x48, 0x52, 0x1f, 0x48, 0x4d, 0x47, 0x40, 0x41, 0x48, 0x53, 0x44, 0x43, 0x9b, 0x13, 0x47, 0x44, 0x51, 0x44, 0x45, 0x4e, 0x51, 0x44, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x9f, 0x4c, 0x54, 0x52, 0x53, 0x1f, 0x41, 0x44, 0x1f, 0x40, 0x1f, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x44, 0x9f, 0x4d, 0x54, 0x4c, 0x41, 0x44, 0x51, 0x1f, 0x4e, 0x45, 0x9f, 0x48, 0x4d, 0x47, 0x40, 0x41, 0x48, 0x53, 0x44, 0x43, 0x1f, 0x56, 0x4e, 0x51, 0x4b, 0x43, 0x52, 0x1b, 0x9f, 0x0, 0x4d, 0x58, 0x1f, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x44, 0x1f, 0x4d, 0x54, 0x4c, 0x41, 0x44, 0x51, 0x9f, 0x43, 0x48, 0x55, 0x48, 0x43, 0x44, 0x43, 0x1f, 0x41, 0x58, 0x9f, ], [0x48, 0x4d, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x58, 0x1f, 0x48, 0x52, 0x1f, 0x40, 0x52, 0x9f, 0x4d, 0x44, 0x40, 0x51, 0x1f, 0x53, 0x4e, 0x1f, 0x4d, 0x4e, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1f, 0x40, 0xd2, 0x4c, 0x40, 0x4a, 0x44, 0x52, 0x1f, 0x4d, 0x4e, 0x1f, 0x4e, 0x43, 0x43, 0x52, 0x1d, 0x1f, 0x52, 0x4e, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x40, 0x55, 0x44, 0x51, 0x40, 0x46, 0x44, 0x9f, 0x4f, 0x4e, 0x4f, 0x54, 0x4b, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1f, 0x4e, 0x45, 0x1f, 0x40, 0x4b, 0x4b, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4f, 0x4b, 0x40, 0x4d, 0x44, 0x53, 0x52, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0xc4, 0x14, 0x4d, 0x48, 0x55, 0x44, 0x51, 0x52, 0x44, 0x1f, 0x42, 0x40, 0x4d, 0x1f, 0x41, 0x44, 0x9f, 0x52, 0x40, 0x48, 0x43, 0x1f, 0x53, 0x4e, 0x1f, 0x41, 0x44, 0x1f, 0x59, 0x44, 0x51, 0x4e, 0x1b, 0x9f, ], [0x5, 0x51, 0x4e, 0x4c, 0x1f, 0x53, 0x47, 0x48, 0x52, 0x1f, 0x48, 0x53, 0x9f, 0x45, 0x4e, 0x4b, 0x4b, 0x4e, 0x56, 0x52, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4f, 0x4e, 0x4f, 0x54, 0x4b, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x56, 0x47, 0x4e, 0x4b, 0x44, 0x1f, 0x14, 0x4d, 0x48, 0x55, 0x44, 0x51, 0x52, 0x44, 0x1f, 0x48, 0x52, 0x9f, 0x40, 0x4b, 0x52, 0x4e, 0x1f, 0x59, 0x44, 0x51, 0x4e, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x40, 0x4d, 0x58, 0x1f, 0x4f, 0x44, 0x4e, 0x4f, 0x4b, 0x44, 0x9f, 0x58, 0x4e, 0x54, 0x1f, 0x4c, 0x40, 0x58, 0x1f, 0x4c, 0x44, 0x44, 0x53, 0x1f, 0x45, 0x51, 0x4e, 0x4c, 0x9f, 0x53, 0x48, 0x4c, 0x44, 0x1f, 0x53, 0x4e, 0x1f, 0x53, 0x48, 0x4c, 0x44, 0x1f, 0x40, 0x51, 0x44, 0x9f, ], [0x4c, 0x44, 0x51, 0x44, 0x4b, 0x58, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4f, 0x51, 0x4e, 0x43, 0x54, 0x42, 0x53, 0x52, 0x1f, 0x4e, 0x45, 0x1f, 0x40, 0x9f, 0x43, 0x44, 0x51, 0x40, 0x4d, 0x46, 0x44, 0x43, 0x9f, 0x48, 0x4c, 0x40, 0x46, 0x48, 0x4d, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1b, 0x9f, 0x1c, 0x0, 0x43, 0x40, 0x4c, 0x52, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x5, 0x40, 0x51, 0x1f, 0x4e, 0x55, 0x44, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4c, 0x48, 0x52, 0x53, 0xd8, 0x4c, 0x4e, 0x54, 0x4d, 0x53, 0x40, 0x48, 0x4d, 0x52, 0x1f, 0x42, 0x4e, 0x4b, 0x43, 0x1f, 0x13, 0x4e, 0x9f, 0x43, 0x54, 0x4d, 0x46, 0x44, 0x4e, 0x4d, 0x52, 0x1f, 0x43, 0x44, 0x44, 0x4f, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x42, 0x40, 0x55, 0x44, 0x51, 0x4d, 0x52, 0x1f, 0x4e, 0x4b, 0x43, 0x1f, 0x16, 0x44, 0x9f, 0x4c, 0x54, 0x52, 0x53, 0x1f, 0x40, 0x56, 0x40, 0x58, 0x1d, 0x1f, 0x44, 0x51, 0x44, 0x9f, 0x41, 0x51, 0x44, 0x40, 0x4a, 0x1f, 0x4e, 0x45, 0x1f, 0x43, 0x40, 0x58, 0x1d, 0x1f, 0x13, 0x4e, 0x9f, 0x52, 0x44, 0x44, 0x4a, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4f, 0x40, 0x4b, 0x44, 0x9f, 0x44, 0x4d, 0x42, 0x47, 0x40, 0x4d, 0x53, 0x44, 0x43, 0x1f, 0x46, 0x4e, 0x4b, 0x43, 0x1b, 0x9f, ], [0x13, 0x47, 0x44, 0x1f, 0x43, 0x56, 0x40, 0x51, 0x55, 0x44, 0x52, 0x1f, 0x4e, 0x45, 0x9f, 0x58, 0x4e, 0x51, 0x44, 0x1f, 0x4c, 0x40, 0x43, 0x44, 0x1f, 0x4c, 0x48, 0x46, 0x47, 0x53, 0x58, 0x9f, 0x52, 0x4f, 0x44, 0x4b, 0x4b, 0x52, 0x1d, 0x1f, 0x16, 0x47, 0x48, 0x4b, 0x44, 0x9f, 0x47, 0x40, 0x4c, 0x4c, 0x44, 0x51, 0x52, 0x1f, 0x45, 0x44, 0x4b, 0x4b, 0x1f, 0x4b, 0x48, 0x4a, 0x44, 0x9f, 0x51, 0x48, 0x4d, 0x46, 0x48, 0x4d, 0x46, 0x1f, 0x41, 0x44, 0x4b, 0x4b, 0x52, 0x1f, 0x8, 0x4d, 0x9f, 0x4f, 0x4b, 0x40, 0x42, 0x44, 0x52, 0x1f, 0x43, 0x44, 0x44, 0x4f, 0x1d, 0x1f, 0x56, 0x47, 0x44, 0x51, 0xc4, 0x43, 0x40, 0x51, 0x4a, 0x1f, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x52, 0x1f, 0x52, 0x4b, 0x44, 0x44, 0x4f, 0x9d, 0x8, 0x4d, 0x1f, 0x47, 0x4e, 0x4b, 0x4b, 0x4e, 0x56, 0x1f, 0x47, 0x40, 0x4b, 0x4b, 0x52, 0x9f, ], [0x41, 0x44, 0x4d, 0x44, 0x40, 0x53, 0x47, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x45, 0x44, 0x4b, 0x4b, 0x52, 0x9b, 0x5, 0x4e, 0x51, 0x1f, 0x40, 0x4d, 0x42, 0x48, 0x44, 0x4d, 0x53, 0x1f, 0x4a, 0x48, 0x4d, 0x46, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x44, 0x4b, 0x55, 0x48, 0x52, 0x47, 0x1f, 0x4b, 0x4e, 0x51, 0x43, 0x9f, 0x13, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x4c, 0x40, 0x4d, 0x58, 0x1f, 0x40, 0x9f, 0x46, 0x4b, 0x44, 0x40, 0x4c, 0x48, 0x4d, 0x46, 0x1f, 0x46, 0x4e, 0x4b, 0x43, 0x44, 0x4d, 0x9f, 0x47, 0x4e, 0x40, 0x51, 0x43, 0x1f, 0x13, 0x47, 0x44, 0x58, 0x1f, 0x52, 0x47, 0x40, 0x4f, 0x44, 0x43, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x56, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x53, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x4b, 0x48, 0x46, 0x47, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x42, 0x40, 0x54, 0x46, 0x47, 0x53, 0x9f, ], [0x13, 0x4e, 0x1f, 0x47, 0x48, 0x43, 0x44, 0x1f, 0x48, 0x4d, 0x1f, 0x46, 0x44, 0x4c, 0x52, 0x1f, 0x4e, 0xcd, 0x47, 0x48, 0x4b, 0x53, 0x1f, 0x4e, 0x45, 0x1f, 0x52, 0x56, 0x4e, 0x51, 0x43, 0x1b, 0x1f, 0xe, 0x4d, 0x9f, 0x52, 0x48, 0x4b, 0x55, 0x44, 0x51, 0x1f, 0x4d, 0x44, 0x42, 0x4a, 0x4b, 0x40, 0x42, 0x44, 0x52, 0x9f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x52, 0x53, 0x51, 0x54, 0x4d, 0x46, 0x1f, 0x13, 0x47, 0x44, 0x9f, 0x45, 0x4b, 0x4e, 0x56, 0x44, 0x51, 0x48, 0x4d, 0x46, 0x1f, 0x52, 0x53, 0x40, 0x51, 0x52, 0x1d, 0x9f, 0x4e, 0x4d, 0x1f, 0x42, 0x51, 0x4e, 0x56, 0x4d, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x58, 0x9f, 0x47, 0x54, 0x4d, 0x46, 0x1f, 0x13, 0x47, 0x44, 0x9f, 0x43, 0x51, 0x40, 0x46, 0x4e, 0x4d, 0x1c, 0x45, 0x48, 0x51, 0x44, 0x1d, 0x1f, 0x48, 0x4d, 0x9f, ], [0x53, 0x56, 0x48, 0x52, 0x53, 0x44, 0x43, 0x1f, 0x56, 0x48, 0x51, 0x44, 0x1f, 0x13, 0x47, 0x44, 0x58, 0x9f, 0x4c, 0x44, 0x52, 0x47, 0x44, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4b, 0x48, 0x46, 0x47, 0x53, 0x9f, 0x4e, 0x45, 0x1f, 0x4c, 0x4e, 0x4e, 0x4d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x52, 0x54, 0x4d, 0x1b, 0x9f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x5, 0x40, 0x51, 0x1f, 0x4e, 0x55, 0x44, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4c, 0x48, 0x52, 0x53, 0xd8, 0x4c, 0x4e, 0x54, 0x4d, 0x53, 0x40, 0x48, 0x4d, 0x52, 0x1f, 0x42, 0x4e, 0x4b, 0x43, 0x1f, 0x13, 0x4e, 0x9f, 0x43, 0x54, 0x4d, 0x46, 0x44, 0x4e, 0x4d, 0x52, 0x1f, 0x43, 0x44, 0x44, 0x4f, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x42, 0x40, 0x55, 0x44, 0x51, 0x4d, 0x52, 0x1f, 0x4e, 0x4b, 0x43, 0x1f, 0x16, 0x44, 0x9f, 0x4c, 0x54, 0x52, 0x53, 0x1f, 0x40, 0x56, 0x40, 0x58, 0x1d, 0x1f, 0x44, 0x51, 0x44, 0x9f, 0x41, 0x51, 0x44, 0x40, 0x4a, 0x1f, 0x4e, 0x45, 0x1f, 0x43, 0x40, 0x58, 0x1d, 0x1f, 0x13, 0x4e, 0x9f, 0x42, 0x4b, 0x40, 0x48, 0x4c, 0x1f, 0x4e, 0x54, 0x51, 0x9f, 0x4b, 0x4e, 0x4d, 0x46, 0x1c, 0x45, 0x4e, 0x51, 0x46, 0x4e, 0x53, 0x53, 0x44, 0x4d, 0x9f, ], [0x46, 0x4e, 0x4b, 0x43, 0x1b, 0x1f, 0x6, 0x4e, 0x41, 0x4b, 0x44, 0x53, 0x52, 0x1f, 0x53, 0x47, 0x44, 0xd8, 0x42, 0x40, 0x51, 0x55, 0x44, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x45, 0x4e, 0x51, 0x9f, 0x53, 0x47, 0x44, 0x4c, 0x52, 0x44, 0x4b, 0x55, 0x44, 0x52, 0x1f, 0x0, 0x4d, 0x43, 0x9f, 0x47, 0x40, 0x51, 0x4f, 0x52, 0x1f, 0x4e, 0x45, 0x1f, 0x46, 0x4e, 0x4b, 0x43, 0x1d, 0x9f, 0x56, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x4d, 0x4e, 0x1f, 0x4c, 0x40, 0x4d, 0x9f, 0x43, 0x44, 0x4b, 0x55, 0x44, 0x52, 0x1f, 0x13, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x4b, 0x40, 0x58, 0x9f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x4b, 0x4e, 0x4d, 0x46, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x4c, 0x40, 0x4d, 0x58, 0x1f, 0x40, 0x1f, 0x52, 0x4e, 0x4d, 0x46, 0x1f, 0x16, 0x40, 0x52, 0x9f, ], [0x52, 0x54, 0x4d, 0x46, 0x1f, 0x54, 0x4d, 0x47, 0x44, 0x40, 0x51, 0x43, 0x1f, 0x41, 0x58, 0x9f, 0x4c, 0x44, 0x4d, 0x1f, 0x4e, 0x51, 0x1f, 0x44, 0x4b, 0x55, 0x44, 0x52, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x9f, 0x4f, 0x48, 0x4d, 0x44, 0x52, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x1f, 0x51, 0x4e, 0x40, 0x51, 0x48, 0x4d, 0xc6, 0x4e, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x47, 0x44, 0x48, 0x46, 0x47, 0x53, 0x1d, 0x1f, 0x13, 0x47, 0xc4, 0x56, 0x48, 0x4d, 0x43, 0x52, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x1f, 0x4c, 0x4e, 0x40, 0x4d, 0x48, 0x4d, 0xc6, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4d, 0x48, 0x46, 0x47, 0x53, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x9f, 0x45, 0x48, 0x51, 0x44, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x51, 0x44, 0x43, 0x1d, 0x1f, 0x48, 0x53, 0x9f, 0x45, 0x4b, 0x40, 0x4c, 0x48, 0x4d, 0x46, 0x1f, 0x52, 0x4f, 0x51, 0x44, 0x40, 0x43, 0x1b, 0x9f, ], [0x13, 0x47, 0x44, 0x1f, 0x53, 0x51, 0x44, 0x44, 0x52, 0x1f, 0x4b, 0x48, 0x4a, 0x44, 0x9f, 0x53, 0x4e, 0x51, 0x42, 0x47, 0x44, 0x52, 0x1f, 0x41, 0x4b, 0x40, 0x59, 0x44, 0x43, 0x9f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x4b, 0x48, 0x46, 0x47, 0x53, 0x1b, 0x9f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x13, 0x47, 0x44, 0x1f, 0x41, 0x44, 0x4b, 0x4b, 0x52, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x9f, 0x51, 0x48, 0x4d, 0x46, 0x48, 0x4d, 0x46, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x43, 0x40, 0x4b, 0x44, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x4c, 0x44, 0x4d, 0x9f, 0x4b, 0x4e, 0x4e, 0x4a, 0x44, 0x43, 0x1f, 0x54, 0x4f, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x9f, 0x45, 0x40, 0x42, 0x44, 0x52, 0x1f, 0x4f, 0x40, 0x4b, 0x44, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x4d, 0x9f, 0x43, 0x51, 0x40, 0x46, 0x4e, 0x4d, 0x5d, 0x52, 0x1f, 0x48, 0x51, 0x44, 0x1f, 0x4c, 0x4e, 0x51, 0x44, 0x9f, 0x45, 0x48, 0x44, 0x51, 0x42, 0x44, 0x1f, 0x53, 0x47, 0x40, 0x4d, 0x1f, 0x45, 0x48, 0x51, 0x44, 0x9f, 0xb, 0x40, 0x48, 0x43, 0x1f, 0x4b, 0x4e, 0x56, 0x1f, 0x53, 0x47, 0x44, 0x48, 0x51, 0x9f, ], [0x53, 0x4e, 0x56, 0x44, 0x51, 0x52, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x47, 0x4e, 0x54, 0x52, 0x44, 0x52, 0x9f, 0x45, 0x51, 0x40, 0x48, 0x4b, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x9f, 0x4c, 0x4e, 0x54, 0x4d, 0x53, 0x40, 0x48, 0x4d, 0x1f, 0x52, 0x4c, 0x4e, 0x4a, 0x44, 0x43, 0x9f, 0x41, 0x44, 0x4d, 0x44, 0x40, 0x53, 0x47, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4c, 0x4e, 0x4e, 0x4d, 0x1b, 0x9f, 0x13, 0x47, 0x44, 0x1f, 0x43, 0x56, 0x40, 0x51, 0x55, 0x44, 0x52, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x58, 0x9f, 0x47, 0x44, 0x40, 0x51, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x53, 0x51, 0x40, 0x4c, 0x4f, 0x1f, 0x4e, 0xc5, 0x43, 0x4e, 0x4e, 0x4c, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x58, 0x1f, 0x45, 0x4b, 0x44, 0x43, 0x9f, 0x53, 0x47, 0x44, 0x48, 0x51, 0x1f, 0x47, 0x40, 0x4b, 0x4b, 0x1d, 0x1f, 0x53, 0x4e, 0x9f, ], [0x43, 0x58, 0x48, 0x4d, 0x46, 0x1f, 0x45, 0x40, 0x4b, 0x4b, 0x1f, 0x1, 0x44, 0x4d, 0x44, 0x40, 0x53, 0xc7, 0x47, 0x48, 0x52, 0x1f, 0x45, 0x44, 0x44, 0x53, 0x1d, 0x1f, 0x41, 0x44, 0x4d, 0x44, 0x40, 0x53, 0x47, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4c, 0x4e, 0x4e, 0x4d, 0x1b, 0x1f, 0x5, 0x40, 0x51, 0x1f, 0x4e, 0x55, 0x44, 0xd1, 0x53, 0x47, 0x44, 0x1f, 0x4c, 0x48, 0x52, 0x53, 0x58, 0x9f, 0x4c, 0x4e, 0x54, 0x4d, 0x53, 0x40, 0x48, 0x4d, 0x52, 0x1f, 0x46, 0x51, 0x48, 0x4c, 0x1f, 0x13, 0x4e, 0x9f, 0x43, 0x54, 0x4d, 0x46, 0x44, 0x4e, 0x4d, 0x52, 0x1f, 0x43, 0x44, 0x44, 0x4f, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x42, 0x40, 0x55, 0x44, 0x51, 0x4d, 0x52, 0x1f, 0x43, 0x48, 0x4c, 0x1f, 0x16, 0x44, 0x9f, 0x4c, 0x54, 0x52, 0x53, 0x1f, 0x40, 0x56, 0x40, 0x58, 0x1d, 0x1f, 0x44, 0x51, 0x44, 0x9f, ], [0x41, 0x51, 0x44, 0x40, 0x4a, 0x1f, 0x4e, 0x45, 0x1f, 0x43, 0x40, 0x58, 0x1d, 0x1f, 0x13, 0x4e, 0x9f, 0x56, 0x48, 0x4d, 0x1f, 0x4e, 0x54, 0x51, 0x1f, 0x47, 0x40, 0x51, 0x4f, 0x52, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x46, 0x4e, 0x4b, 0x43, 0x1f, 0x45, 0x51, 0x4e, 0x4c, 0x1f, 0x47, 0x48, 0x4c, 0x1a, 0x9f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x11, 0x4e, 0x40, 0x43, 0x52, 0x1f, 0x46, 0x4e, 0x1f, 0x44, 0x55, 0x44, 0x51, 0x1f, 0x44, 0x55, 0x44, 0xd1, 0x4e, 0x4d, 0x1d, 0x1f, 0xe, 0x55, 0x44, 0x51, 0x1f, 0x51, 0x4e, 0x42, 0x4a, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x54, 0x4d, 0x43, 0x44, 0x51, 0x1f, 0x53, 0x51, 0x44, 0x44, 0x1d, 0x1f, 0x1, 0x58, 0x9f, 0x42, 0x40, 0x55, 0x44, 0x52, 0x1f, 0x56, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x4d, 0x44, 0x55, 0x44, 0x51, 0x9f, 0x52, 0x54, 0x4d, 0x1f, 0x47, 0x40, 0x52, 0x1f, 0x52, 0x47, 0x4e, 0x4d, 0x44, 0x1d, 0x1f, 0x1, 0x58, 0x9f, 0x52, 0x53, 0x51, 0x44, 0x40, 0x4c, 0x52, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x4d, 0x44, 0x55, 0x44, 0xd1, 0x45, 0x48, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x44, 0x40, 0x1b, 0x1f, 0xe, 0x55, 0x44, 0xd1, 0x52, 0x4d, 0x4e, 0x56, 0x1f, 0x41, 0x58, 0x1f, 0x56, 0x48, 0x4d, 0x53, 0x44, 0x51, 0x9f, ], [0x52, 0x4e, 0x56, 0x4d, 0x1d, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4c, 0x44, 0x51, 0x51, 0x58, 0x1f, 0x45, 0x4b, 0x4e, 0x56, 0x44, 0x51, 0x52, 0x9f, 0x4e, 0x45, 0x1f, 0x9, 0x54, 0x4d, 0x44, 0x1d, 0x1f, 0xe, 0x55, 0x44, 0x51, 0x9f, 0x46, 0x51, 0x40, 0x52, 0x52, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x4e, 0x55, 0x44, 0x51, 0x9f, 0x52, 0x53, 0x4e, 0x4d, 0x44, 0x1d, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x54, 0x4d, 0x43, 0x44, 0x51, 0x9f, 0x4c, 0x4e, 0x54, 0x4d, 0x53, 0x40, 0x48, 0x4d, 0x52, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4c, 0x4e, 0x4e, 0x4d, 0x1b, 0x1f, 0x11, 0x4e, 0x40, 0x43, 0x52, 0x1f, 0x46, 0x4e, 0x9f, 0x44, 0x55, 0x44, 0x51, 0x1f, 0x44, 0x55, 0x44, 0x51, 0x1f, 0x4e, 0x4d, 0x1f, 0x14, 0x4d, 0x43, 0x44, 0xd1, ], [0x42, 0x4b, 0x4e, 0x54, 0x43, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x54, 0x4d, 0x43, 0x44, 0x51, 0x9f, 0x52, 0x53, 0x40, 0x51, 0x1d, 0x1f, 0x18, 0x44, 0x53, 0x1f, 0x45, 0x44, 0x44, 0x53, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x56, 0x40, 0x4d, 0x43, 0x44, 0x51, 0x48, 0x4d, 0x46, 0x9f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x46, 0x4e, 0x4d, 0x44, 0x1f, 0x13, 0x54, 0x51, 0x4d, 0x1f, 0x40, 0x53, 0x9f, 0x4b, 0x40, 0x52, 0x53, 0x1f, 0x53, 0x4e, 0x1f, 0x47, 0x4e, 0x4c, 0x44, 0x1f, 0x40, 0x45, 0x40, 0x51, 0x9b, 0x4, 0x58, 0x44, 0x52, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x45, 0x48, 0x51, 0x44, 0x1f, 0x40, 0x4d, 0xc3, 0x52, 0x56, 0x4e, 0x51, 0x43, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x52, 0x44, 0x44, 0x4d, 0x9f, 0x0, 0x4d, 0x43, 0x1f, 0x47, 0x4e, 0x51, 0x51, 0x4e, 0x51, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x9f, ], [0x47, 0x40, 0x4b, 0x4b, 0x52, 0x1f, 0x4e, 0x45, 0x1f, 0x52, 0x53, 0x4e, 0x4d, 0x44, 0x9f, 0xb, 0x4e, 0x4e, 0x4a, 0x1f, 0x40, 0x53, 0x1f, 0x4b, 0x40, 0x52, 0x53, 0x1f, 0x4e, 0x4d, 0x9f, 0x4c, 0x44, 0x40, 0x43, 0x4e, 0x56, 0x52, 0x1f, 0x46, 0x51, 0x44, 0x44, 0x4d, 0x1f, 0x0, 0x4d, 0x43, 0x9f, 0x53, 0x51, 0x44, 0x44, 0x52, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x47, 0x48, 0x4b, 0x4b, 0x52, 0x9f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x4b, 0x4e, 0x4d, 0x46, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x9f, 0x4a, 0x4d, 0x4e, 0x56, 0x4d, 0x1b, 0x1f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x13, 0x47, 0x51, 0x44, 0x44, 0x1f, 0x11, 0x48, 0x4d, 0x46, 0x52, 0x1f, 0x45, 0x4e, 0x51, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4, 0x4b, 0x55, 0x44, 0x4d, 0x1c, 0x4a, 0x48, 0x4d, 0x46, 0x52, 0x9f, 0x54, 0x4d, 0x43, 0x44, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x4a, 0x58, 0x1d, 0x9f, 0x12, 0x44, 0x55, 0x44, 0x4d, 0x1f, 0x45, 0x4e, 0x51, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x3, 0x56, 0x40, 0x51, 0x45, 0x1c, 0x4b, 0x4e, 0x51, 0x43, 0x52, 0x1f, 0x48, 0x4d, 0x9f, 0x53, 0x47, 0x44, 0x48, 0x51, 0x1f, 0x47, 0x40, 0x4b, 0x4b, 0x52, 0x1f, 0x4e, 0x45, 0x9f, 0x52, 0x53, 0x4e, 0x4d, 0x44, 0x1d, 0x1f, 0xd, 0x48, 0x4d, 0x44, 0x1f, 0x45, 0x4e, 0x51, 0x9f, 0xc, 0x4e, 0x51, 0x53, 0x40, 0x4b, 0x1f, 0xc, 0x44, 0x4d, 0x1f, 0x43, 0x4e, 0x4e, 0x4c, 0x44, 0x43, 0x9f, ], [0x53, 0x4e, 0x1f, 0x43, 0x48, 0x44, 0x1d, 0x1f, 0xe, 0x4d, 0x44, 0x1f, 0x45, 0x4e, 0x51, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x3, 0x40, 0x51, 0x4a, 0x1f, 0xb, 0x4e, 0x51, 0x43, 0x1f, 0x4e, 0x4d, 0x9f, 0x47, 0x48, 0x52, 0x1f, 0x43, 0x40, 0x51, 0x4a, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x4d, 0x44, 0x1f, 0x8, 0xcd, 0x53, 0x47, 0x44, 0x1f, 0xb, 0x40, 0x4d, 0x43, 0x1f, 0x4e, 0x45, 0x1f, 0xc, 0x4e, 0x51, 0x43, 0x4e, 0xd1, 0x56, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x12, 0x47, 0x40, 0x43, 0x4e, 0x56, 0x52, 0x9f, 0x4b, 0x48, 0x44, 0x1b, 0x1f, 0xe, 0x4d, 0x44, 0x1f, 0x11, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x4e, 0x9f, 0x51, 0x54, 0x4b, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x40, 0x4b, 0x4b, 0x1d, 0x1f, 0xe, 0x4d, 0xc4, 0x11, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x4e, 0x1f, 0x45, 0x48, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x4c, 0x9d, ], [0xe, 0x4d, 0x44, 0x1f, 0x11, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x4e, 0x1f, 0x41, 0x51, 0x48, 0x4d, 0x46, 0x9f, 0x53, 0x47, 0x44, 0x4c, 0x1f, 0x40, 0x4b, 0x4b, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x48, 0x4d, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x43, 0x40, 0x51, 0x4a, 0x4d, 0x44, 0x52, 0x52, 0x1f, 0x41, 0x48, 0x4d, 0x43, 0x9f, 0x53, 0x47, 0x44, 0x4c, 0x1d, 0x1f, 0x8, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0xb, 0x40, 0x4d, 0x43, 0x9f, 0x4e, 0x45, 0x1f, 0xc, 0x4e, 0x51, 0x43, 0x4e, 0x51, 0x1f, 0x56, 0x47, 0x44, 0x51, 0x44, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x12, 0x47, 0x40, 0x43, 0x4e, 0x56, 0x52, 0x1f, 0x4b, 0x48, 0x44, 0x1b, 0x9f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, ]],
|
||||
[[0x0, 0x4b, 0x4b, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x46, 0x4e, 0x4b, 0x43, 0x9f, 0x43, 0x4e, 0x44, 0x52, 0x1f, 0x4d, 0x4e, 0x53, 0x1f, 0x46, 0x4b, 0x48, 0x53, 0x53, 0x44, 0x51, 0x1d, 0x9f, 0xd, 0x4e, 0x53, 0x1f, 0x40, 0x4b, 0x4b, 0x1f, 0x53, 0x47, 0x4e, 0x52, 0x44, 0x1f, 0x56, 0x47, 0x4e, 0x9f, 0x56, 0x40, 0x4d, 0x43, 0x44, 0x51, 0x1f, 0x40, 0x51, 0x44, 0x1f, 0x4b, 0x4e, 0x52, 0x53, 0x1b, 0x9f, 0x13, 0x47, 0x44, 0x1f, 0x4e, 0x4b, 0x43, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x48, 0x52, 0x9f, 0x52, 0x53, 0x51, 0x4e, 0x4d, 0x46, 0x1f, 0x43, 0x4e, 0x44, 0x52, 0x1f, 0x4d, 0x4e, 0x53, 0x9f, 0x56, 0x48, 0x53, 0x47, 0x44, 0x51, 0x1d, 0x1f, 0x3, 0x44, 0x44, 0x4f, 0x1f, 0x51, 0x4e, 0x4e, 0x53, 0xd2, 0x40, 0x51, 0x44, 0x1f, 0x4d, 0x4e, 0x53, 0x1f, 0x51, 0x44, 0x40, 0x42, 0x47, 0x44, 0x43, 0x1f, 0x41, 0xd8, ], [0x53, 0x47, 0x44, 0x1f, 0x45, 0x51, 0x4e, 0x52, 0x53, 0x1b, 0x1f, 0x5, 0x51, 0x4e, 0x4c, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x40, 0x52, 0x47, 0x44, 0x52, 0x1f, 0x40, 0x1f, 0x45, 0x48, 0x51, 0x44, 0x9f, 0x52, 0x47, 0x40, 0x4b, 0x4b, 0x1f, 0x41, 0x44, 0x1f, 0x56, 0x4e, 0x4a, 0x44, 0x4d, 0x1d, 0x1f, 0x0, 0x9f, 0x4b, 0x48, 0x46, 0x47, 0x53, 0x1f, 0x45, 0x51, 0x4e, 0x4c, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x52, 0x47, 0x40, 0x43, 0x4e, 0x56, 0x52, 0x1f, 0x52, 0x47, 0x40, 0x4b, 0x4b, 0x9f, 0x52, 0x4f, 0x51, 0x48, 0x4d, 0x46, 0x1b, 0x1f, 0x11, 0x44, 0x4d, 0x44, 0x56, 0x44, 0x43, 0x9f, 0x52, 0x47, 0x40, 0x4b, 0x4b, 0x1f, 0x41, 0x44, 0x1f, 0x41, 0x4b, 0x40, 0x43, 0x44, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x41, 0x51, 0x4e, 0x4a, 0x44, 0x4d, 0x1d, 0x9f, ], [0x13, 0x47, 0x44, 0x1f, 0x42, 0x51, 0x4e, 0x56, 0x4d, 0x4b, 0x44, 0x52, 0x52, 0x9f, 0x40, 0x46, 0x40, 0x48, 0x4d, 0x1f, 0x52, 0x47, 0x40, 0x4b, 0x4b, 0x1f, 0x41, 0x44, 0x9f, 0x4a, 0x48, 0x4d, 0x46, 0x1b, 0x1f, 0x1c, 0x13, 0x4e, 0x4b, 0x4a, 0x48, 0x44, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x16, 0x47, 0x4e, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x52, 0x1d, 0x1f, 0x2, 0x40, 0x4d, 0x1b, 0x9f, 0x16, 0x47, 0x4e, 0x1f, 0x53, 0x51, 0x48, 0x44, 0x52, 0x1d, 0x1f, 0x3, 0x4e, 0x44, 0x52, 0x1b, 0x9f, 0x16, 0x47, 0x4e, 0x1f, 0x4b, 0x4e, 0x55, 0x44, 0x52, 0x1d, 0x1f, 0xb, 0x48, 0x55, 0x44, 0x52, 0x1b, 0x9f, 0x1c, 0xc, 0x42, 0x2, 0x40, 0x45, 0x45, 0x51, 0x44, 0x58, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x6, 0x4e, 0x4d, 0x44, 0x1f, 0x40, 0x56, 0x40, 0x58, 0x1d, 0x1f, 0x46, 0x4e, 0x4d, 0x44, 0x9f, 0x40, 0x47, 0x44, 0x40, 0x43, 0x1d, 0x1f, 0x4, 0x42, 0x47, 0x4e, 0x44, 0x52, 0x1f, 0x51, 0x4e, 0x4b, 0xcb, 0x54, 0x4d, 0x40, 0x4d, 0x52, 0x56, 0x44, 0x51, 0x44, 0x43, 0x1b, 0x1f, 0x4, 0x4c, 0x4f, 0x53, 0x58, 0x9d, 0x4e, 0x4f, 0x44, 0x4d, 0x1d, 0x1f, 0x43, 0x54, 0x52, 0x53, 0x58, 0x1d, 0x1f, 0x43, 0x44, 0x40, 0x43, 0x9d, 0x16, 0x47, 0x58, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x40, 0x4b, 0x4b, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x16, 0x44, 0x58, 0x51, 0x45, 0x4e, 0x4b, 0x4a, 0x1f, 0x45, 0x4b, 0x44, 0x43, 0x1e, 0x9f, 0x16, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x43, 0x51, 0x40, 0x46, 0x4e, 0x4d, 0xd2, 0x46, 0x4e, 0x4d, 0x44, 0x1f, 0x53, 0x4e, 0x46, 0x44, 0x53, 0x47, 0x44, 0x51, 0x1e, 0x9f, ], [0xb, 0x44, 0x40, 0x55, 0x48, 0x4d, 0x46, 0x1f, 0x16, 0x44, 0x58, 0x51, 0x52, 0x1f, 0x53, 0x4e, 0x9f, 0x56, 0x48, 0x4d, 0x43, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x56, 0x44, 0x40, 0x53, 0x47, 0x44, 0x51, 0x1e, 0x9f, 0x12, 0x44, 0x53, 0x53, 0x48, 0x4d, 0x46, 0x1f, 0x47, 0x44, 0x51, 0x43, 0x41, 0x44, 0x40, 0x52, 0x53, 0xd2, 0x45, 0x51, 0x44, 0x44, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x44, 0x53, 0x47, 0x44, 0x51, 0x1e, 0x9f, 0x6, 0x4e, 0x4d, 0x44, 0x1d, 0x1f, 0x4e, 0x54, 0x51, 0x9f, 0x52, 0x40, 0x45, 0x44, 0x46, 0x54, 0x40, 0x51, 0x43, 0x52, 0x1d, 0x1f, 0x46, 0x4e, 0x4d, 0x44, 0x1d, 0x9f, 0x41, 0x54, 0x53, 0x1f, 0x56, 0x47, 0x48, 0x53, 0x47, 0x44, 0x51, 0x1e, 0x1f, 0x7, 0x40, 0x55, 0x44, 0x9f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x45, 0x4b, 0x4e, 0x56, 0x4d, 0x1f, 0x53, 0x4e, 0x1f, 0x52, 0x4e, 0x4c, 0xc4, ], [0x4d, 0x44, 0x56, 0x1f, 0x16, 0x44, 0x58, 0x51, 0x1f, 0x16, 0x47, 0x44, 0x4d, 0x9f, 0x42, 0x51, 0x54, 0x44, 0x4b, 0x1f, 0x13, 0x47, 0x51, 0x44, 0x40, 0x43, 0x52, 0x1f, 0x52, 0x4e, 0x4c, 0xc4, 0x4e, 0x53, 0x47, 0x44, 0x51, 0x52, 0x1f, 0x45, 0x44, 0x40, 0x51, 0x1e, 0x1f, 0x0, 0x51, 0x44, 0x9f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x56, 0x4e, 0x51, 0x4b, 0x43, 0x52, 0x1f, 0x40, 0x56, 0x40, 0x58, 0x9f, 0x45, 0x51, 0x4e, 0x4c, 0x1f, 0x47, 0x44, 0x51, 0x44, 0x1e, 0x1f, 0x16, 0x47, 0x58, 0x1d, 0x9f, 0x4e, 0x47, 0x1d, 0x1f, 0x56, 0x47, 0x58, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x44, 0x4c, 0x4f, 0x53, 0xd8, 0x16, 0x44, 0x58, 0x51, 0x1e, 0x1f, 0x1c, 0xc, 0x42, 0x2, 0x40, 0x45, 0x45, 0x51, 0x44, 0x58, 0x1f, 0x9f, 0x9f, ]],
|
||||
[[0xc, 0x51, 0x1b, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0xc, 0x51, 0x52, 0x1b, 0x9f, 0x3, 0x54, 0x51, 0x52, 0x4b, 0x44, 0x58, 0x1d, 0x1f, 0x4e, 0x45, 0x1f, 0x4d, 0x54, 0x4c, 0x41, 0x44, 0xd1, 0x45, 0x4e, 0x54, 0x51, 0x1d, 0x1f, 0xf, 0x51, 0x48, 0x55, 0x44, 0x53, 0x9f, 0x3, 0x51, 0x48, 0x55, 0x44, 0x1d, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x1f, 0x4f, 0x51, 0x4e, 0x54, 0x43, 0x9f, 0x53, 0x4e, 0x1f, 0x52, 0x40, 0x58, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x58, 0x9f, 0x56, 0x44, 0x51, 0x44, 0x1f, 0x4f, 0x44, 0x51, 0x45, 0x44, 0x42, 0x53, 0x4b, 0x58, 0x9f, 0x4d, 0x4e, 0x51, 0x4c, 0x40, 0x4b, 0x1d, 0x1f, 0x53, 0x47, 0x40, 0x4d, 0x4a, 0x1f, 0x58, 0x4e, 0x54, 0x9f, 0x55, 0x44, 0x51, 0x58, 0x1f, 0x4c, 0x54, 0x42, 0x47, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x58, 0x9f, ], [0x56, 0x44, 0x51, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4b, 0x40, 0x52, 0x53, 0x9f, 0x4f, 0x44, 0x4e, 0x4f, 0x4b, 0x44, 0x1f, 0x58, 0x4e, 0x54, 0x5d, 0x43, 0x9f, 0x44, 0x57, 0x4f, 0x44, 0x42, 0x53, 0x1f, 0x53, 0x4e, 0x1f, 0x41, 0x44, 0x9f, 0x48, 0x4d, 0x55, 0x4e, 0x4b, 0x55, 0x44, 0x43, 0x1f, 0x48, 0x4d, 0x9f, 0x40, 0x4d, 0x58, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1f, 0x52, 0x53, 0x51, 0x40, 0x4d, 0x46, 0x44, 0x9f, 0x4e, 0x51, 0x1f, 0x4c, 0x58, 0x52, 0x53, 0x44, 0x51, 0x48, 0x4e, 0x54, 0x52, 0x1d, 0x9f, 0x41, 0x44, 0x42, 0x40, 0x54, 0x52, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x58, 0x1f, 0x49, 0x54, 0x52, 0x53, 0x9f, 0x43, 0x48, 0x43, 0x4d, 0x5d, 0x53, 0x1f, 0x47, 0x4e, 0x4b, 0x43, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x9f, ], [0x52, 0x54, 0x42, 0x47, 0x1f, 0x4d, 0x4e, 0x4d, 0x52, 0x44, 0x4d, 0x52, 0x44, 0x1b, 0x9f, 0x1c, 0x11, 0x4e, 0x56, 0x4b, 0x48, 0x4d, 0x46, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0xb, 0x4e, 0x55, 0x44, 0x1d, 0x1f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x9f, 0x50, 0x54, 0x48, 0x42, 0x4a, 0x4b, 0x58, 0x1f, 0x40, 0x51, 0x51, 0x44, 0x52, 0x53, 0x52, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x46, 0x44, 0x4d, 0x53, 0x4b, 0x44, 0x1f, 0x47, 0x44, 0x40, 0x51, 0x53, 0x1d, 0x9f, 0x12, 0x44, 0x48, 0x59, 0x44, 0x43, 0x1f, 0x47, 0x48, 0x4c, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x4c, 0xd8, 0x41, 0x44, 0x40, 0x54, 0x53, 0x48, 0x45, 0x54, 0x4b, 0x1f, 0x45, 0x4e, 0x51, 0x4c, 0x9f, 0x13, 0x47, 0x40, 0x53, 0x1f, 0x56, 0x40, 0x52, 0x1f, 0x53, 0x40, 0x4a, 0x44, 0x4d, 0x9f, 0x45, 0x51, 0x4e, 0x4c, 0x1f, 0x4c, 0x44, 0x1d, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0x9f, 0x4c, 0x40, 0x4d, 0x4d, 0x44, 0x51, 0x1f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x52, 0x53, 0x48, 0x4b, 0xcb, ], [0x46, 0x51, 0x48, 0x44, 0x55, 0x44, 0x52, 0x1f, 0x4c, 0x44, 0x1b, 0x1f, 0xb, 0x4e, 0x55, 0x44, 0x1d, 0x9f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x4f, 0x40, 0x51, 0x43, 0x4e, 0x4d, 0x52, 0x1f, 0x4d, 0x4e, 0x9f, 0x41, 0x44, 0x4b, 0x4e, 0x55, 0x44, 0x43, 0x1f, 0x45, 0x51, 0x4e, 0x4c, 0x9f, 0x4b, 0x4e, 0x55, 0x48, 0x4d, 0x46, 0x1d, 0x1f, 0x53, 0x4e, 0x4e, 0x4a, 0x1f, 0x4c, 0x44, 0x1f, 0x52, 0xce, 0x52, 0x53, 0x51, 0x4e, 0x4d, 0x46, 0x4b, 0x58, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x9f, 0x43, 0x44, 0x4b, 0x48, 0x46, 0x47, 0x53, 0x1f, 0x48, 0x4d, 0x1f, 0x47, 0x48, 0x4c, 0x9f, 0x13, 0x47, 0x40, 0x53, 0x1d, 0x1f, 0x40, 0x52, 0x1f, 0x58, 0x4e, 0x54, 0x1f, 0x52, 0x44, 0x44, 0x1d, 0x9f, 0x48, 0x53, 0x1f, 0x52, 0x53, 0x48, 0x4b, 0x4b, 0x1f, 0x40, 0x41, 0x40, 0x4d, 0x43, 0x4e, 0x4d, 0x52, 0x9f, ], [0x4c, 0x44, 0x1f, 0x4d, 0x4e, 0x53, 0x1b, 0x1b, 0x1b, 0x9f, 0x1c, 0x0, 0x4b, 0x48, 0x46, 0x47, 0x48, 0x44, 0x51, 0x48, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x8, 0x1f, 0x42, 0x40, 0x4d, 0x4d, 0x4e, 0x53, 0x1f, 0x44, 0x57, 0x4f, 0x51, 0x44, 0x52, 0x52, 0x9f, 0x48, 0x53, 0x1d, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x52, 0x54, 0x51, 0x44, 0x4b, 0x58, 0x1f, 0x58, 0x4e, 0xd4, 0x40, 0x4d, 0x43, 0x1f, 0x44, 0x55, 0x44, 0x51, 0x58, 0x41, 0x4e, 0x43, 0x58, 0x1f, 0x47, 0x40, 0x55, 0xc4, 0x40, 0x1f, 0x4d, 0x4e, 0x53, 0x48, 0x4e, 0x4d, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x9f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x48, 0x52, 0x1f, 0x4e, 0x51, 0x1f, 0x52, 0x47, 0x4e, 0x54, 0x4b, 0xc3, 0x41, 0x44, 0x1f, 0x40, 0x4d, 0x1f, 0x44, 0x57, 0x48, 0x52, 0x53, 0x44, 0x4d, 0x42, 0x44, 0x1f, 0x4e, 0xc5, 0x58, 0x4e, 0x54, 0x51, 0x52, 0x1f, 0x41, 0x44, 0x58, 0x4e, 0x4d, 0x43, 0x1f, 0x58, 0x4e, 0x54, 0x1b, 0x9f, 0x16, 0x47, 0x40, 0x53, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x54, 0x52, 0x44, 0x9f, ], [0x4e, 0x45, 0x1f, 0x4c, 0x58, 0x1f, 0x42, 0x51, 0x44, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1d, 0x1f, 0x48, 0xc5, 0x8, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x1f, 0x44, 0x4d, 0x53, 0x48, 0x51, 0x44, 0x4b, 0x58, 0x9f, 0x42, 0x4e, 0x4d, 0x53, 0x40, 0x48, 0x4d, 0x44, 0x43, 0x1f, 0x47, 0x44, 0x51, 0x44, 0x1e, 0x1f, 0xc, 0xd8, 0x46, 0x51, 0x44, 0x40, 0x53, 0x1f, 0x4c, 0x48, 0x52, 0x44, 0x51, 0x48, 0x44, 0x52, 0x1f, 0x48, 0x4d, 0x9f, 0x53, 0x47, 0x48, 0x52, 0x1f, 0x56, 0x4e, 0x51, 0x4b, 0x43, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x9f, 0x41, 0x44, 0x44, 0x4d, 0x1f, 0x7, 0x44, 0x40, 0x53, 0x47, 0x42, 0x4b, 0x48, 0x45, 0x45, 0x5d, 0x52, 0x9f, 0x4c, 0x48, 0x52, 0x44, 0x51, 0x48, 0x44, 0x52, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x8, 0x9f, 0x56, 0x40, 0x53, 0x42, 0x47, 0x44, 0x43, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x45, 0x44, 0x4b, 0x53, 0x9f, ], [0x44, 0x40, 0x42, 0x47, 0x1f, 0x45, 0x51, 0x4e, 0x4c, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x41, 0x44, 0x46, 0x48, 0x4d, 0x4d, 0x48, 0x4d, 0x46, 0x1b, 0x1f, 0x4c, 0x58, 0x9f, 0x46, 0x51, 0x44, 0x40, 0x53, 0x1f, 0x53, 0x47, 0x4e, 0x54, 0x46, 0x47, 0x53, 0x1f, 0x48, 0x4d, 0x9f, 0x4b, 0x48, 0x55, 0x48, 0x4d, 0x46, 0x1f, 0x48, 0x52, 0x1f, 0x47, 0x48, 0x4c, 0x52, 0x44, 0x4b, 0x45, 0x9b, 0x8, 0x45, 0x1f, 0x40, 0x4b, 0x4b, 0x1f, 0x44, 0x4b, 0x52, 0x44, 0x9f, 0x4f, 0x44, 0x51, 0x48, 0x52, 0x47, 0x44, 0x43, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x47, 0x44, 0x9f, 0x51, 0x44, 0x4c, 0x40, 0x48, 0x4d, 0x44, 0x43, 0x1d, 0x1f, 0x8, 0x1f, 0x52, 0x47, 0x4e, 0x54, 0x4b, 0xc3, 0x52, 0x53, 0x48, 0x4b, 0x4b, 0x1f, 0x42, 0x4e, 0x4d, 0x53, 0x48, 0x4d, 0x54, 0x44, 0x1f, 0x53, 0x4e, 0x9f, ], [0x41, 0x44, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x48, 0x45, 0x1f, 0x40, 0x4b, 0x4b, 0x9f, 0x44, 0x4b, 0x52, 0x44, 0x1f, 0x51, 0x44, 0x4c, 0x40, 0x48, 0x4d, 0x44, 0x43, 0x1d, 0x1f, 0x40, 0x4d, 0xc3, 0x47, 0x44, 0x1f, 0x56, 0x44, 0x51, 0x44, 0x9f, 0x40, 0x4d, 0x4d, 0x48, 0x47, 0x48, 0x4b, 0x40, 0x53, 0x44, 0x43, 0x1d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x54, 0x4d, 0x48, 0x55, 0x44, 0x51, 0x52, 0x44, 0x1f, 0x56, 0x4e, 0x54, 0x4b, 0x43, 0x9f, 0x53, 0x54, 0x51, 0x4d, 0x1f, 0x53, 0x4e, 0x1f, 0x40, 0x1f, 0x4c, 0x48, 0x46, 0x47, 0x53, 0x58, 0x9f, 0x52, 0x53, 0x51, 0x40, 0x4d, 0x46, 0x44, 0x51, 0x1b, 0x1f, 0x8, 0x1f, 0x52, 0x47, 0x4e, 0x54, 0x4b, 0xc3, 0x4d, 0x4e, 0x53, 0x1f, 0x52, 0x44, 0x44, 0x4c, 0x1f, 0x40, 0x1f, 0x4f, 0x40, 0x51, 0x53, 0x1f, 0x4e, 0xc5, ], [0x48, 0x53, 0x1b, 0x1f, 0x1c, 0x1, 0x51, 0x4e, 0x4d, 0x53, 0x44, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x8, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x43, 0x51, 0x44, 0x40, 0x4c, 0x53, 0x1f, 0x48, 0x4d, 0x9f, 0x4c, 0x58, 0x1f, 0x4b, 0x48, 0x45, 0x44, 0x1d, 0x1f, 0x43, 0x51, 0x44, 0x40, 0x4c, 0x52, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x52, 0x53, 0x40, 0x58, 0x44, 0x43, 0x9f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x4c, 0x44, 0x1f, 0x44, 0x55, 0x44, 0x51, 0x9f, 0x40, 0x45, 0x53, 0x44, 0x51, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x42, 0x47, 0x40, 0x4d, 0x46, 0x44, 0xc3, 0x4c, 0x58, 0x1f, 0x48, 0x43, 0x44, 0x40, 0x52, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x58, 0x9f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x46, 0x4e, 0x4d, 0x44, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x1f, 0x4c, 0x44, 0x1d, 0x9f, ], [0x4b, 0x48, 0x4a, 0x44, 0x1f, 0x56, 0x48, 0x4d, 0x44, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x9f, 0x56, 0x40, 0x53, 0x44, 0x51, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x40, 0x4b, 0x53, 0x44, 0x51, 0x44, 0xc3, 0x53, 0x47, 0x44, 0x1f, 0x42, 0x4e, 0x4b, 0x4e, 0x51, 0x1f, 0x4e, 0x45, 0x1f, 0x4c, 0x58, 0x9f, 0x4c, 0x48, 0x4d, 0x43, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x48, 0x52, 0x1f, 0x48, 0x52, 0x9f, 0x4e, 0x4d, 0x44, 0x1b, 0x1f, 0x8, 0x5d, 0x4c, 0x1f, 0x46, 0x4e, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x4e, 0x9f, 0x53, 0x44, 0x4b, 0x4b, 0x1f, 0x48, 0x53, 0x1f, 0x1c, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x53, 0x40, 0x4a, 0xc4, 0x42, 0x40, 0x51, 0x44, 0x1f, 0x4d, 0x4e, 0x53, 0x1f, 0x53, 0x4e, 0x1f, 0x52, 0x4c, 0x48, 0x4b, 0x44, 0x9f, 0x40, 0x53, 0x1f, 0x40, 0x4d, 0x58, 0x1f, 0x4f, 0x40, 0x51, 0x53, 0x1f, 0x4e, 0x45, 0x1f, 0x48, 0x53, 0x9b, ], [0x1c, 0x1, 0x51, 0x4e, 0x4d, 0x53, 0x44, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x13, 0x47, 0x48, 0x52, 0x1f, 0x52, 0x53, 0x4e, 0x51, 0x58, 0x1f, 0x52, 0x47, 0x40, 0x4b, 0x4b, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x1f, 0x4c, 0x40, 0x4d, 0x1f, 0x53, 0x44, 0x40, 0x42, 0xc7, 0x47, 0x48, 0x52, 0x1f, 0x52, 0x4e, 0x4d, 0x1d, 0x1f, 0x0, 0x4d, 0x43, 0x9f, 0x2, 0x51, 0x48, 0x52, 0x4f, 0x48, 0x4d, 0x1f, 0x2, 0x51, 0x48, 0x52, 0x4f, 0x48, 0x40, 0x4d, 0x9f, 0x52, 0x47, 0x40, 0x4b, 0x4b, 0x1f, 0x4d, 0x44, 0x5d, 0x44, 0x51, 0x1f, 0x46, 0x4e, 0x1f, 0x41, 0x58, 0x9d, 0x5, 0x51, 0x4e, 0x4c, 0x1f, 0x53, 0x47, 0x48, 0x52, 0x1f, 0x43, 0x40, 0x58, 0x1f, 0x53, 0x4e, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x44, 0x4d, 0x43, 0x48, 0x4d, 0x46, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x56, 0x4e, 0x51, 0x4b, 0x43, 0x1d, 0x1f, 0x1, 0x54, 0x53, 0x1f, 0x56, 0x44, 0x1f, 0x48, 0x4d, 0x9f, ], [0x48, 0x53, 0x1f, 0x52, 0x47, 0x40, 0x4b, 0x4b, 0x1f, 0x41, 0x44, 0x9f, 0x51, 0x44, 0x4c, 0x44, 0x4c, 0x41, 0x44, 0x51, 0x44, 0x43, 0x1b, 0x1f, 0x16, 0x44, 0x9f, 0x45, 0x44, 0x56, 0x1d, 0x1f, 0x56, 0x44, 0x1f, 0x47, 0x40, 0x4f, 0x4f, 0x58, 0x1f, 0x45, 0x44, 0x56, 0x9d, 0x56, 0x44, 0x1f, 0x41, 0x40, 0x4d, 0x43, 0x1f, 0x4e, 0x45, 0x9f, 0x41, 0x51, 0x4e, 0x53, 0x47, 0x44, 0x51, 0x52, 0x1b, 0x1f, 0x5, 0x4e, 0x51, 0x1f, 0x47, 0x44, 0x9f, 0x53, 0x4e, 0x1c, 0x43, 0x40, 0x58, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x52, 0x47, 0x44, 0x43, 0x52, 0x9f, 0x47, 0x48, 0x52, 0x1f, 0x41, 0x4b, 0x4e, 0x4e, 0x43, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x4c, 0x44, 0x9f, 0x12, 0x47, 0x40, 0x4b, 0x4b, 0x1f, 0x41, 0x44, 0x1f, 0x4c, 0x58, 0x9f, ], [0x41, 0x51, 0x4e, 0x53, 0x47, 0x44, 0x51, 0x1b, 0x9f, 0x1c, 0x12, 0x47, 0x40, 0x4a, 0x44, 0x52, 0x4f, 0x44, 0x40, 0x51, 0x44, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x7, 0x4e, 0x56, 0x44, 0x55, 0x44, 0x51, 0x1f, 0x4c, 0x44, 0x40, 0x4d, 0x1f, 0x58, 0x4e, 0x54, 0x51, 0x9f, 0x4b, 0x48, 0x45, 0x44, 0x1f, 0x48, 0x52, 0x1d, 0x1f, 0x4c, 0x44, 0x44, 0x53, 0x1f, 0x48, 0x53, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x4b, 0x48, 0x55, 0x44, 0x1f, 0x48, 0x53, 0x1b, 0x1f, 0x3, 0x4e, 0x9f, 0x4d, 0x4e, 0x53, 0x1f, 0x52, 0x47, 0x54, 0x4d, 0x1f, 0x48, 0x53, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x42, 0x40, 0x4b, 0x4b, 0x1f, 0x48, 0x53, 0x1f, 0x47, 0x40, 0x51, 0x43, 0x9f, 0x4d, 0x40, 0x4c, 0x44, 0x52, 0x1b, 0x1f, 0x8, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x4d, 0x4e, 0x53, 0x9f, 0x52, 0x4e, 0x1f, 0x41, 0x40, 0x43, 0x1f, 0x40, 0x52, 0x1f, 0x58, 0x4e, 0x54, 0x1f, 0x40, 0x51, 0x44, 0x9b, 0x8, 0x53, 0x1f, 0x4b, 0x4e, 0x4e, 0x4a, 0x52, 0x1f, 0x4f, 0x4e, 0x4e, 0x51, 0x44, 0x52, 0x53, 0x9f, ], [0x56, 0x47, 0x44, 0x4d, 0x1f, 0x58, 0x4e, 0x54, 0x1f, 0x40, 0x51, 0x44, 0x9f, 0x51, 0x48, 0x42, 0x47, 0x44, 0x52, 0x53, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x9f, 0x45, 0x40, 0x54, 0x4b, 0x53, 0x1c, 0x45, 0x48, 0x4d, 0x43, 0x44, 0x51, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x9f, 0x45, 0x48, 0x4d, 0x43, 0x1f, 0x45, 0x40, 0x54, 0x4b, 0x53, 0x52, 0x1f, 0x44, 0x55, 0x44, 0x4d, 0x9f, 0x48, 0x4d, 0x1f, 0x4f, 0x40, 0x51, 0x40, 0x43, 0x48, 0x52, 0x44, 0x1b, 0x1f, 0xb, 0x4e, 0x55, 0x44, 0x9f, 0x58, 0x4e, 0x54, 0x51, 0x1f, 0x4b, 0x48, 0x45, 0x44, 0x1d, 0x1f, 0x4f, 0x4e, 0x4e, 0x51, 0x1f, 0x40, 0xd2, 0x48, 0x53, 0x1f, 0x48, 0x52, 0x1b, 0x1f, 0x18, 0x4e, 0x54, 0x1f, 0x4c, 0x40, 0x58, 0x9f, 0x4f, 0x44, 0x51, 0x47, 0x40, 0x4f, 0x52, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x52, 0x4e, 0x4c, 0x44, 0x9f, ], [0x4f, 0x4b, 0x44, 0x40, 0x52, 0x40, 0x4d, 0x53, 0x1d, 0x9f, 0x53, 0x47, 0x51, 0x48, 0x4b, 0x4b, 0x48, 0x4d, 0x46, 0x1d, 0x9f, 0x46, 0x4b, 0x4e, 0x51, 0x48, 0x4e, 0x54, 0x52, 0x1f, 0x47, 0x4e, 0x54, 0x51, 0x52, 0x1d, 0x9f, 0x44, 0x55, 0x44, 0x4d, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0x9f, 0x4f, 0x4e, 0x4e, 0x51, 0x47, 0x4e, 0x54, 0x52, 0x44, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x9f, 0x52, 0x44, 0x53, 0x53, 0x48, 0x4d, 0x46, 0x1f, 0x52, 0x54, 0x4d, 0x1f, 0x48, 0x52, 0x9f, 0x51, 0x44, 0x45, 0x4b, 0x44, 0x42, 0x53, 0x44, 0x43, 0x1f, 0x45, 0x51, 0x4e, 0x4c, 0x1f, 0x53, 0x47, 0xc4, 0x56, 0x48, 0x4d, 0x43, 0x4e, 0x56, 0x52, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0x44, 0x9f, ], [0x40, 0x4b, 0x4c, 0x52, 0x47, 0x4e, 0x54, 0x52, 0x44, 0x1f, 0x40, 0x52, 0x9f, 0x41, 0x51, 0x48, 0x46, 0x47, 0x53, 0x4b, 0x58, 0x1f, 0x40, 0x52, 0x1f, 0x45, 0x51, 0x4e, 0x4c, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x51, 0x48, 0x42, 0x47, 0x1f, 0x4c, 0x40, 0x4d, 0x5d, 0x52, 0x9f, 0x40, 0x41, 0x4e, 0x43, 0x44, 0x1b, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x4d, 0x4e, 0x56, 0x9f, 0x4c, 0x44, 0x4b, 0x53, 0x52, 0x1f, 0x41, 0x44, 0x45, 0x4e, 0x51, 0x44, 0x1f, 0x48, 0x53, 0x52, 0x9f, 0x43, 0x4e, 0x4e, 0x51, 0x1f, 0x40, 0x52, 0x1f, 0x44, 0x40, 0x51, 0x4b, 0x58, 0x1f, 0x48, 0x4d, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x52, 0x4f, 0x51, 0x48, 0x4d, 0x46, 0x1b, 0x1f, 0x8, 0x1f, 0x43, 0x4e, 0x9f, 0x4d, 0x4e, 0x53, 0x1f, 0x52, 0x44, 0x44, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x40, 0x9f, ], [0x50, 0x54, 0x48, 0x44, 0x53, 0x1f, 0x4c, 0x48, 0x4d, 0x43, 0x1f, 0x4c, 0x40, 0x58, 0x9f, 0x4b, 0x48, 0x55, 0x44, 0x1f, 0x40, 0x52, 0x9f, 0x42, 0x4e, 0x4d, 0x53, 0x44, 0x4d, 0x53, 0x44, 0x43, 0x4b, 0x58, 0x1f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x9d, 0x40, 0x4d, 0x43, 0x1f, 0x47, 0x40, 0x55, 0x44, 0x1f, 0x40, 0x52, 0x9f, 0x42, 0x47, 0x44, 0x44, 0x51, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x47, 0x4e, 0x54, 0x46, 0x47, 0x53, 0x52, 0x9d, 0x40, 0x52, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0x1f, 0x4f, 0x40, 0x4b, 0x40, 0x42, 0x44, 0x1b, 0x9f, 0x1c, 0x13, 0x47, 0x4e, 0x51, 0x44, 0x40, 0x54, 0x1f, 0x9f, 0x9f, ]],
|
||||
[[0x16, 0x44, 0x1f, 0x4c, 0x54, 0x52, 0x53, 0x1f, 0x4b, 0x44, 0x40, 0x51, 0x4d, 0x1f, 0x53, 0x4e, 0x9f, 0x51, 0x44, 0x40, 0x56, 0x40, 0x4a, 0x44, 0x4d, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x4a, 0x44, 0x44, 0x4f, 0x9f, 0x4e, 0x54, 0x51, 0x52, 0x44, 0x4b, 0x55, 0x44, 0x52, 0x1f, 0x40, 0x56, 0x40, 0x4a, 0x44, 0x1d, 0x9f, 0x4d, 0x4e, 0x53, 0x1f, 0x41, 0x58, 0x1f, 0x4c, 0x44, 0x42, 0x47, 0x40, 0x4d, 0x48, 0x42, 0x40, 0x4b, 0x9f, 0x40, 0x48, 0x43, 0x52, 0x1d, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x41, 0x58, 0x1f, 0x40, 0x4d, 0x9f, 0x48, 0x4d, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x44, 0x9f, 0x44, 0x57, 0x4f, 0x44, 0x42, 0x53, 0x40, 0x53, 0x48, 0x4e, 0x4d, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0xc4, 0x43, 0x40, 0x56, 0x4d, 0x1d, 0x1f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x43, 0x4e, 0x44, 0x52, 0x9f, ], [0x4d, 0x4e, 0x53, 0x1f, 0x45, 0x4e, 0x51, 0x52, 0x40, 0x4a, 0x44, 0x1f, 0x54, 0x52, 0x9f, 0x44, 0x55, 0x44, 0x4d, 0x1f, 0x48, 0x4d, 0x1f, 0x4e, 0x54, 0x51, 0x9f, 0x52, 0x4e, 0x54, 0x4d, 0x43, 0x44, 0x52, 0x53, 0x1f, 0x52, 0x4b, 0x44, 0x44, 0x4f, 0x1b, 0x1f, 0x8, 0x9f, 0x4a, 0x4d, 0x4e, 0x56, 0x1f, 0x4e, 0x45, 0x1f, 0x4d, 0x4e, 0x1f, 0x4c, 0x4e, 0x51, 0x44, 0x9f, 0x44, 0x4d, 0x42, 0x4e, 0x54, 0x51, 0x40, 0x46, 0x48, 0x4d, 0x46, 0x1f, 0x45, 0x40, 0x42, 0x53, 0x9f, 0x53, 0x47, 0x40, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x54, 0x4d, 0x50, 0x54, 0x44, 0x52, 0x53, 0x48, 0x4e, 0x4d, 0x40, 0x41, 0x4b, 0x44, 0x9f, 0x40, 0x41, 0x48, 0x4b, 0x48, 0x53, 0x58, 0x1f, 0x4e, 0x45, 0x1f, 0x4c, 0x40, 0x4d, 0x1f, 0x53, 0x4e, 0x9f, ], [0x44, 0x4b, 0x44, 0x55, 0x40, 0x53, 0x44, 0x1f, 0x47, 0x48, 0x52, 0x1f, 0x4b, 0x48, 0x45, 0x44, 0x9f, 0x41, 0x58, 0x1f, 0x40, 0x1f, 0x42, 0x4e, 0x4d, 0x52, 0x42, 0x48, 0x4e, 0x54, 0x52, 0x9f, 0x44, 0x4d, 0x43, 0x44, 0x40, 0x55, 0x4e, 0x54, 0x51, 0x1b, 0x1f, 0x8, 0x53, 0x1f, 0x48, 0x52, 0x9f, 0x52, 0x4e, 0x4c, 0x44, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x4e, 0x1f, 0x41, 0x44, 0x9f, 0x40, 0x41, 0x4b, 0x44, 0x1f, 0x53, 0x4e, 0x1f, 0x4f, 0x40, 0x48, 0x4d, 0x53, 0x1f, 0x40, 0x9f, 0x4f, 0x40, 0x51, 0x53, 0x48, 0x42, 0x54, 0x4b, 0x40, 0x51, 0x9f, 0x4f, 0x48, 0x42, 0x53, 0x54, 0x51, 0x44, 0x1d, 0x1f, 0x4e, 0x51, 0x1f, 0x53, 0x4e, 0x9f, 0x42, 0x40, 0x51, 0x55, 0x44, 0x1f, 0x40, 0x1f, 0x52, 0x53, 0x40, 0x53, 0x54, 0x44, 0x1d, 0x9f, ], [0x40, 0x4d, 0x43, 0x1f, 0x52, 0x4e, 0x1f, 0x53, 0x4e, 0x1f, 0x4c, 0x40, 0x4a, 0x44, 0x1f, 0x40, 0x9f, 0x45, 0x44, 0x56, 0x1f, 0x4e, 0x41, 0x49, 0x44, 0x42, 0x53, 0x52, 0x9f, 0x41, 0x44, 0x40, 0x54, 0x53, 0x48, 0x45, 0x54, 0x4b, 0x1d, 0x1f, 0x41, 0x54, 0x53, 0x1f, 0x48, 0x53, 0x9f, 0x48, 0x52, 0x1f, 0x45, 0x40, 0x51, 0x1f, 0x4c, 0x4e, 0x51, 0x44, 0x9f, 0x46, 0x4b, 0x4e, 0x51, 0x48, 0x4e, 0x54, 0x52, 0x1f, 0x53, 0x4e, 0x1f, 0x42, 0x40, 0x51, 0x55, 0x44, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x4f, 0x40, 0x48, 0x4d, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x55, 0x44, 0x51, 0xd8, 0x40, 0x53, 0x4c, 0x4e, 0x52, 0x4f, 0x47, 0x44, 0x51, 0x44, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x4c, 0x44, 0x43, 0x48, 0x54, 0x4c, 0x1f, 0x53, 0x47, 0x51, 0x4e, 0x54, 0x46, 0x47, 0x9f, ], [0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x56, 0x44, 0x1f, 0x4b, 0x4e, 0x4e, 0x4a, 0x1d, 0x9f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x4c, 0x4e, 0x51, 0x40, 0x4b, 0x4b, 0x58, 0x1f, 0x56, 0x44, 0x9f, 0x42, 0x40, 0x4d, 0x1f, 0x43, 0x4e, 0x1b, 0x1f, 0x13, 0x4e, 0x1f, 0x40, 0x45, 0x45, 0x44, 0x42, 0x53, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x50, 0x54, 0x40, 0x4b, 0x48, 0x53, 0x58, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0xc4, 0x43, 0x40, 0x58, 0x1d, 0x1f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x48, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x47, 0x48, 0x46, 0x47, 0x44, 0x52, 0x53, 0x1f, 0x4e, 0x45, 0x1f, 0x40, 0x51, 0x53, 0x52, 0x1b, 0x9f, 0x1c, 0x13, 0x47, 0x4e, 0x51, 0x44, 0x40, 0x54, 0x1f, 0x9f, 0x9f, ]],
|
||||
[[0x8, 0x45, 0x1f, 0x4e, 0x4d, 0x44, 0x1f, 0x40, 0x43, 0x55, 0x40, 0x4d, 0x42, 0x44, 0x52, 0x9f, 0x42, 0x4e, 0x4d, 0x45, 0x48, 0x43, 0x44, 0x4d, 0x53, 0x4b, 0x58, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0xc4, 0x43, 0x48, 0x51, 0x44, 0x42, 0x53, 0x48, 0x4e, 0x4d, 0x1f, 0x4e, 0x45, 0x1f, 0x47, 0x48, 0x52, 0x9f, 0x43, 0x51, 0x44, 0x40, 0x4c, 0x52, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x44, 0x4d, 0x43, 0x44, 0x40, 0x55, 0x4e, 0x51, 0x52, 0x1f, 0x53, 0x4e, 0x1f, 0x4b, 0x48, 0x55, 0x44, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4b, 0x48, 0x45, 0x44, 0x1f, 0x56, 0x47, 0x48, 0x42, 0x47, 0x1f, 0x47, 0x44, 0x9f, 0x47, 0x40, 0x52, 0x1f, 0x48, 0x4c, 0x40, 0x46, 0x48, 0x4d, 0x44, 0x43, 0x1d, 0x1f, 0x47, 0x44, 0x9f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x4c, 0x44, 0x44, 0x53, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x1f, 0x40, 0x9f, ], [0x52, 0x54, 0x42, 0x42, 0x44, 0x52, 0x52, 0x1f, 0x54, 0x4d, 0x44, 0x57, 0x4f, 0x44, 0x42, 0x53, 0x44, 0xc3, 0x48, 0x4d, 0x1f, 0x42, 0x4e, 0x4c, 0x4c, 0x4e, 0x4d, 0x1f, 0x47, 0x4e, 0x54, 0x51, 0x52, 0x1b, 0x9f, 0x7, 0x44, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x4f, 0x54, 0x53, 0x1f, 0x52, 0x4e, 0x4c, 0x44, 0x9f, 0x53, 0x47, 0x48, 0x4d, 0x46, 0x52, 0x1f, 0x41, 0x44, 0x47, 0x48, 0x4d, 0x43, 0x1d, 0x9f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x4f, 0x40, 0x52, 0x52, 0x1f, 0x40, 0x4d, 0x9f, 0x48, 0x4d, 0x55, 0x48, 0x52, 0x48, 0x41, 0x4b, 0x44, 0x9f, 0x41, 0x4e, 0x54, 0x4d, 0x43, 0x40, 0x51, 0x58, 0x1b, 0x1f, 0xd, 0x44, 0x56, 0x1d, 0x9f, 0x54, 0x4d, 0x48, 0x55, 0x44, 0x51, 0x52, 0x40, 0x4b, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, ], [0x4c, 0x4e, 0x51, 0x44, 0x1f, 0x4b, 0x48, 0x41, 0x44, 0x51, 0x40, 0x4b, 0x1f, 0x4b, 0x40, 0x56, 0x52, 0x9f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x41, 0x44, 0x46, 0x48, 0x4d, 0x1f, 0x53, 0x4e, 0x9f, 0x44, 0x52, 0x53, 0x40, 0x41, 0x4b, 0x48, 0x52, 0x47, 0x9f, 0x53, 0x47, 0x44, 0x4c, 0x52, 0x44, 0x4b, 0x55, 0x44, 0x52, 0x1f, 0x40, 0x51, 0x4e, 0x54, 0x4d, 0x43, 0x9f, 0x40, 0x4d, 0x43, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x48, 0x4d, 0x1f, 0x47, 0x48, 0x4c, 0x1d, 0x1f, 0x4e, 0xd1, 0x53, 0x47, 0x44, 0x1f, 0x4e, 0x4b, 0x43, 0x1f, 0x4b, 0x40, 0x56, 0x52, 0x1f, 0x41, 0x44, 0x9f, 0x44, 0x57, 0x4f, 0x40, 0x4d, 0x43, 0x44, 0x43, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x48, 0x4d, 0x53, 0x44, 0x51, 0x4f, 0x51, 0x44, 0x53, 0x44, 0x43, 0x1f, 0x48, 0x4d, 0x1f, 0x47, 0x48, 0xd2, ], [0x45, 0x40, 0x55, 0x4e, 0x51, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0x1f, 0x4c, 0x4e, 0x51, 0x44, 0x9f, 0x4b, 0x48, 0x41, 0x44, 0x51, 0x40, 0x4b, 0x1f, 0x52, 0x44, 0x4d, 0x52, 0x44, 0x1d, 0x1f, 0x40, 0x4d, 0xc3, 0x47, 0x44, 0x1f, 0x56, 0x48, 0x4b, 0x4b, 0x1f, 0x4b, 0x48, 0x55, 0x44, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x9f, 0x53, 0x47, 0x44, 0x1f, 0x4b, 0x48, 0x42, 0x44, 0x4d, 0x52, 0x44, 0x1f, 0x4e, 0x45, 0x1f, 0x40, 0x9f, 0x47, 0x48, 0x46, 0x47, 0x44, 0x51, 0x1f, 0x4e, 0x51, 0x43, 0x44, 0x51, 0x1f, 0x4e, 0x45, 0x9f, 0x41, 0x44, 0x48, 0x4d, 0x46, 0x52, 0x1b, 0x1f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x8, 0x5d, 0x4c, 0x1f, 0x4d, 0x4e, 0x41, 0x4e, 0x43, 0x58, 0x1a, 0x1f, 0x16, 0x47, 0x4e, 0x9f, 0x40, 0x51, 0x44, 0x1f, 0x58, 0x4e, 0x54, 0x1e, 0x1f, 0x0, 0x51, 0x44, 0x1f, 0x58, 0x4e, 0x54, 0x9f, 0x4d, 0x4e, 0x41, 0x4e, 0x43, 0x58, 0x1d, 0x1f, 0x53, 0x4e, 0x4e, 0x1e, 0x1f, 0x13, 0x47, 0x44, 0x4d, 0x9f, 0x53, 0x47, 0x44, 0x51, 0x44, 0x5d, 0x52, 0x1f, 0x40, 0x1f, 0x4f, 0x40, 0x48, 0x51, 0x1f, 0x4e, 0x45, 0x9f, 0x54, 0x52, 0x1d, 0x1f, 0x43, 0x4e, 0x4d, 0x5d, 0x53, 0x1f, 0x53, 0x44, 0x4b, 0x4b, 0x1a, 0x9f, 0x13, 0x47, 0x44, 0x58, 0x5d, 0x43, 0x1f, 0x41, 0x40, 0x4d, 0x48, 0x52, 0x47, 0x1f, 0x54, 0x52, 0x1d, 0x9f, 0x58, 0x4e, 0x54, 0x1f, 0x4a, 0x4d, 0x4e, 0x56, 0x1b, 0x1f, 0x7, 0x4e, 0x56, 0x9f, 0x43, 0x51, 0x44, 0x40, 0x51, 0x58, 0x1f, 0x53, 0x4e, 0x1f, 0x41, 0x44, 0x9f, ], [0x52, 0x4e, 0x4c, 0x44, 0x41, 0x4e, 0x43, 0x58, 0x1a, 0x1f, 0x7, 0x4e, 0x56, 0x9f, 0x4f, 0x54, 0x41, 0x4b, 0x48, 0x42, 0x1d, 0x1f, 0x4b, 0x48, 0x4a, 0x44, 0x1f, 0x40, 0x9f, 0x45, 0x51, 0x4e, 0x46, 0x1f, 0x13, 0x4e, 0x1f, 0x53, 0x44, 0x4b, 0x4b, 0x1f, 0x58, 0x4e, 0x54, 0x51, 0x9f, 0x4d, 0x40, 0x4c, 0x44, 0x1f, 0x53, 0x47, 0x44, 0x1f, 0x4b, 0x48, 0x55, 0x44, 0x4b, 0x4e, 0x4d, 0x46, 0x9f, 0x43, 0x40, 0x58, 0x1f, 0x13, 0x4e, 0x1f, 0x40, 0x4d, 0x1f, 0x40, 0x43, 0x4c, 0x48, 0x51, 0x48, 0x4d, 0xc6, 0x41, 0x4e, 0x46, 0x1a, 0x1f, 0x1c, 0x3, 0x48, 0x42, 0x4a, 0x48, 0x4d, 0x52, 0x4e, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x7, 0x4e, 0x56, 0x1f, 0x47, 0x40, 0x4f, 0x4f, 0x58, 0x1f, 0x48, 0x52, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x4b, 0x48, 0x53, 0x53, 0x4b, 0x44, 0x1f, 0x52, 0x53, 0x4e, 0x4d, 0x44, 0x1f, 0x13, 0x47, 0x40, 0x53, 0x9f, 0x51, 0x40, 0x4c, 0x41, 0x4b, 0x44, 0x52, 0x1f, 0x48, 0x4d, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x51, 0x4e, 0x40, 0x43, 0x1f, 0x40, 0x4b, 0x4e, 0x4d, 0x44, 0x1d, 0x1f, 0x0, 0x4d, 0x43, 0x9f, 0x43, 0x4e, 0x44, 0x52, 0x4d, 0x5d, 0x53, 0x1f, 0x42, 0x40, 0x51, 0x44, 0x1f, 0x40, 0x41, 0x4e, 0x54, 0xd3, 0x42, 0x40, 0x51, 0x44, 0x44, 0x51, 0x52, 0x1d, 0x1f, 0x0, 0x4d, 0x43, 0x9f, 0x44, 0x57, 0x48, 0x46, 0x44, 0x4d, 0x42, 0x48, 0x44, 0x52, 0x1f, 0x4d, 0x44, 0x55, 0x44, 0x51, 0x9f, 0x45, 0x44, 0x40, 0x51, 0x52, 0x1b, 0x1f, 0x16, 0x47, 0x4e, 0x52, 0x44, 0x1f, 0x42, 0x4e, 0x40, 0x53, 0x9f, ], [0x4e, 0x45, 0x1f, 0x44, 0x4b, 0x44, 0x4c, 0x44, 0x4d, 0x53, 0x40, 0x4b, 0x1f, 0x41, 0x51, 0x4e, 0x56, 0xcd, 0x0, 0x1f, 0x4f, 0x40, 0x52, 0x52, 0x48, 0x4d, 0x46, 0x1f, 0x54, 0x4d, 0x48, 0x55, 0x44, 0x51, 0x52, 0xc4, 0x4f, 0x54, 0x53, 0x1f, 0x4e, 0x4d, 0x1b, 0x1f, 0x0, 0x4d, 0x43, 0x9f, 0x48, 0x4d, 0x43, 0x44, 0x4f, 0x44, 0x4d, 0x43, 0x44, 0x4d, 0x53, 0x1f, 0x40, 0x52, 0x1f, 0x53, 0x47, 0xc4, 0x52, 0x54, 0x4d, 0x1d, 0x1f, 0x0, 0x52, 0x52, 0x4e, 0x42, 0x48, 0x40, 0x53, 0x44, 0x52, 0x1f, 0x4e, 0xd1, 0x46, 0x4b, 0x4e, 0x56, 0x52, 0x1f, 0x40, 0x4b, 0x4e, 0x4d, 0x44, 0x1d, 0x9f, 0x5, 0x54, 0x4b, 0x45, 0x48, 0x4b, 0x4b, 0x48, 0x4d, 0x46, 0x9f, 0x40, 0x41, 0x52, 0x4e, 0x4b, 0x54, 0x53, 0x44, 0x1f, 0x43, 0x44, 0x42, 0x51, 0x44, 0x44, 0x1f, 0x8, 0xcd, ], [0x42, 0x40, 0x52, 0x54, 0x40, 0x4b, 0x1f, 0x52, 0x48, 0x4c, 0x4f, 0x4b, 0x48, 0x42, 0x48, 0x53, 0x58, 0x9b, 0x1c, 0x3, 0x48, 0x42, 0x4a, 0x48, 0x4d, 0x52, 0x4e, 0x4d, 0x1f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, ]],
|
||||
[[0x1, 0x44, 0x42, 0x40, 0x54, 0x52, 0x44, 0x1f, 0x8, 0x1f, 0x42, 0x4e, 0x54, 0x4b, 0x43, 0x9f, 0x4d, 0x4e, 0x53, 0x1f, 0x52, 0x53, 0x4e, 0x4f, 0x1f, 0x45, 0x4e, 0x51, 0x1f, 0x43, 0x44, 0x40, 0x53, 0xc7, 0x7, 0x44, 0x1f, 0x4a, 0x48, 0x4d, 0x43, 0x4b, 0x58, 0x1f, 0x52, 0x53, 0x4e, 0x4f, 0x4f, 0x44, 0x43, 0x9f, 0x45, 0x4e, 0x51, 0x1f, 0x4c, 0x44, 0x1b, 0x1f, 0x13, 0x47, 0x44, 0x9f, 0x42, 0x40, 0x51, 0x51, 0x48, 0x40, 0x46, 0x44, 0x1f, 0x47, 0x44, 0x4b, 0x43, 0x1f, 0x41, 0x54, 0x53, 0x9f, 0x49, 0x54, 0x52, 0x53, 0x1f, 0x4e, 0x54, 0x51, 0x52, 0x44, 0x4b, 0x55, 0x44, 0x52, 0x1f, 0x0, 0x4d, 0xc3, 0x48, 0x4c, 0x4c, 0x4e, 0x51, 0x53, 0x40, 0x4b, 0x48, 0x53, 0x58, 0x9f, 0x1c, 0x3, 0x48, 0x42, 0x4a, 0x48, 0x4d, 0x52, 0x4e, 0x4d, 0x1f, 0x9f, ]],
|
||||
[[0x5, 0x4e, 0x51, 0x1d, 0x1f, 0x4b, 0x48, 0x4a, 0x44, 0x1f, 0x40, 0x4b, 0x4c, 0x4e, 0x52, 0x53, 0x9f, 0x44, 0x55, 0x44, 0x51, 0x58, 0x4e, 0x4d, 0x44, 0x1f, 0x44, 0x4b, 0x52, 0x44, 0x1f, 0x48, 0x4d, 0x9f, 0x4e, 0x54, 0x51, 0x1f, 0x42, 0x4e, 0x54, 0x4d, 0x53, 0x51, 0x58, 0x1d, 0x1f, 0x8, 0x9f, 0x52, 0x53, 0x40, 0x51, 0x53, 0x44, 0x43, 0x1f, 0x4e, 0x54, 0x53, 0x1f, 0x56, 0x48, 0x53, 0x47, 0x9f, 0x4c, 0x58, 0x1f, 0x52, 0x47, 0x40, 0x51, 0x44, 0x1f, 0x4e, 0x45, 0x9f, 0x4e, 0x4f, 0x53, 0x48, 0x4c, 0x48, 0x52, 0x4c, 0x1b, 0x1f, 0x8, 0x9f, 0x41, 0x44, 0x4b, 0x48, 0x44, 0x55, 0x44, 0x43, 0x1f, 0x48, 0x4d, 0x1f, 0x47, 0x40, 0x51, 0x43, 0x9f, 0x56, 0x4e, 0x51, 0x4a, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x4f, 0x51, 0x4e, 0x46, 0x51, 0x44, 0x52, 0x52, 0x9f, ], [0x40, 0x4d, 0x43, 0x1f, 0x40, 0x42, 0x53, 0x48, 0x4e, 0x4d, 0x1d, 0x1f, 0x41, 0x54, 0x53, 0x9f, 0x4d, 0x4e, 0x56, 0x1d, 0x1f, 0x40, 0x45, 0x53, 0x44, 0x51, 0x1f, 0x45, 0x48, 0x51, 0x52, 0x53, 0x9f, 0x41, 0x44, 0x48, 0x4d, 0x46, 0x1f, 0x5d, 0x45, 0x4e, 0x51, 0x5d, 0x9f, 0x52, 0x4e, 0x42, 0x48, 0x44, 0x53, 0x58, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x53, 0x47, 0x44, 0x4d, 0x9f, 0x5d, 0x40, 0x46, 0x40, 0x48, 0x4d, 0x52, 0x53, 0x5d, 0x1f, 0x48, 0x53, 0x1d, 0x1f, 0x8, 0x9f, 0x40, 0x52, 0x52, 0x48, 0x46, 0x4d, 0x1f, 0x4c, 0x58, 0x52, 0x44, 0x4b, 0x45, 0x1f, 0x4d, 0x4e, 0x9f, 0x51, 0x40, 0x4d, 0x4a, 0x1f, 0x4e, 0x51, 0x1f, 0x40, 0x4d, 0x58, 0x1f, 0x4b, 0x48, 0x4c, 0x48, 0x53, 0x9d, 0x40, 0x4d, 0x43, 0x1f, 0x52, 0x54, 0x42, 0x47, 0x1f, 0x40, 0x4d, 0x9f, ], [0x40, 0x53, 0x53, 0x48, 0x53, 0x54, 0x43, 0x44, 0x1f, 0x48, 0x52, 0x1f, 0x55, 0x44, 0x51, 0x58, 0x9f, 0x4c, 0x54, 0x42, 0x47, 0x1f, 0x40, 0x46, 0x40, 0x48, 0x4d, 0x52, 0x53, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x53, 0x51, 0x44, 0x4d, 0x43, 0x1f, 0x4e, 0x45, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x53, 0x48, 0x4c, 0x44, 0x52, 0x1b, 0x1f, 0x1, 0x54, 0x53, 0x1f, 0x4c, 0x58, 0x9f, 0x56, 0x4e, 0x51, 0x4b, 0x43, 0x1f, 0x47, 0x40, 0x52, 0x1f, 0x41, 0x44, 0x42, 0x4e, 0x4c, 0x44, 0x9f, 0x4e, 0x4d, 0x44, 0x1f, 0x4e, 0x45, 0x1f, 0x48, 0x4d, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x44, 0x9f, 0x4f, 0x4e, 0x52, 0x52, 0x48, 0x41, 0x48, 0x4b, 0x48, 0x53, 0x48, 0x44, 0x52, 0x1b, 0x9f, 0x16, 0x47, 0x40, 0x53, 0x1f, 0x40, 0x1f, 0x4f, 0x47, 0x51, 0x40, 0x52, 0x44, 0x1f, 0x1c, 0x9f, ], [0x52, 0x53, 0x48, 0x4b, 0x4b, 0x1f, 0x48, 0x53, 0x5d, 0x52, 0x1f, 0x40, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x9f, 0x4f, 0x47, 0x51, 0x40, 0x52, 0x44, 0x1f, 0x40, 0x4d, 0x43, 0x1f, 0x40, 0x1f, 0x46, 0x4e, 0x4e, 0x43, 0x9f, 0x55, 0x48, 0x44, 0x56, 0x1f, 0x4e, 0x45, 0x1f, 0x4b, 0x48, 0x45, 0x44, 0x1d, 0x1f, 0x40, 0x4d, 0x43, 0x9f, 0x40, 0x1f, 0x4c, 0x40, 0x4d, 0x1f, 0x52, 0x47, 0x4e, 0x54, 0x4b, 0x43, 0x4d, 0x5d, 0x53, 0x9f, 0x40, 0x42, 0x42, 0x44, 0x4f, 0x53, 0x1f, 0x40, 0x4d, 0x58, 0x1f, 0x4e, 0x53, 0x47, 0x44, 0x51, 0x1b, 0x9f, 0x53, 0x47, 0x40, 0x53, 0x1f, 0x4c, 0x54, 0x42, 0x47, 0x1f, 0x8, 0x5d, 0x55, 0x44, 0x9f, 0x4b, 0x44, 0x40, 0x51, 0x4d, 0x44, 0x43, 0x9f, 0x54, 0x4d, 0x43, 0x44, 0x51, 0x46, 0x51, 0x4e, 0x54, 0x4d, 0x43, 0x1b, 0x1f, 0x14, 0x4d, 0x53, 0x48, 0xcb, ], [0x52, 0x4e, 0x4c, 0x44, 0x1f, 0x46, 0x40, 0x4d, 0x46, 0x1f, 0x52, 0x54, 0x42, 0x42, 0x44, 0x44, 0x43, 0xd2, 0x48, 0x4d, 0x1f, 0x4f, 0x54, 0x53, 0x53, 0x48, 0x4d, 0x46, 0x1f, 0x53, 0x47, 0x44, 0x9f, 0x56, 0x4e, 0x51, 0x4b, 0x43, 0x1f, 0x48, 0x4d, 0x1f, 0x40, 0x1f, 0x52, 0x53, 0x51, 0x40, 0x48, 0x53, 0x9f, 0x49, 0x40, 0x42, 0x4a, 0x44, 0x53, 0x1d, 0x1f, 0x48, 0x53, 0x52, 0x9f, 0x43, 0x44, 0x45, 0x48, 0x4d, 0x48, 0x53, 0x48, 0x4e, 0x4d, 0x1f, 0x48, 0x52, 0x9f, 0x4f, 0x4e, 0x52, 0x52, 0x48, 0x41, 0x48, 0x4b, 0x48, 0x53, 0x58, 0x1b, 0x9f, 0x1c, 0x4, 0x4b, 0x4b, 0x48, 0x52, 0x4e, 0x4d, 0x1f, 0x9f, 0x9f, ]],
|
||||
]
|
||||
364
worlds/smw/Names/LocationName.py
Normal file
364
worlds/smw/Names/LocationName.py
Normal file
@@ -0,0 +1,364 @@
|
||||
# Level Definitions
|
||||
yoshis_house = "Yoshi's House"
|
||||
yoshis_house_tile = "Yoshi's House - Tile"
|
||||
|
||||
yoshis_island_1_exit_1 = "Yoshi's Island 1 - Normal Exit"
|
||||
yoshis_island_1_dragon = "Yoshi's Island 1 - Dragon Coins"
|
||||
yoshis_island_2_exit_1 = "Yoshi's Island 2 - Normal Exit"
|
||||
yoshis_island_2_dragon = "Yoshi's Island 2 - Dragon Coins"
|
||||
yoshis_island_3_exit_1 = "Yoshi's Island 3 - Normal Exit"
|
||||
yoshis_island_3_dragon = "Yoshi's Island 3 - Dragon Coins"
|
||||
yoshis_island_4_exit_1 = "Yoshi's Island 4 - Normal Exit"
|
||||
yoshis_island_4_dragon = "Yoshi's Island 4 - Dragon Coins"
|
||||
yoshis_island_castle = "#1 Iggy's Castle - Normal Exit"
|
||||
yoshis_island_koopaling = "#1 Iggy's Castle - Boss"
|
||||
|
||||
yellow_switch_palace = "Yellow Switch Palace"
|
||||
|
||||
donut_plains_1_exit_1 = "Donut Plains 1 - Normal Exit"
|
||||
donut_plains_1_exit_2 = "Donut Plains 1 - Secret Exit"
|
||||
donut_plains_1_dragon = "Donut Plains 1 - Dragon Coins"
|
||||
donut_plains_2_exit_1 = "Donut Plains 2 - Normal Exit"
|
||||
donut_plains_2_exit_2 = "Donut Plains 2 - Secret Exit"
|
||||
donut_plains_2_dragon = "Donut Plains 2 - Dragon Coins"
|
||||
donut_plains_3_exit_1 = "Donut Plains 3 - Normal Exit"
|
||||
donut_plains_3_dragon = "Donut Plains 3 - Dragon Coins"
|
||||
donut_plains_4_exit_1 = "Donut Plains 4 - Normal Exit"
|
||||
donut_plains_4_dragon = "Donut Plains 4 - Dragon Coins"
|
||||
donut_secret_1_exit_1 = "Donut Secret 1 - Normal Exit"
|
||||
donut_secret_1_exit_2 = "Donut Secret 1 - Secret Exit"
|
||||
donut_secret_1_dragon = "Donut Secret 1 - Dragon Coins"
|
||||
donut_secret_2_exit_1 = "Donut Secret 2 - Normal Exit"
|
||||
donut_secret_2_dragon = "Donut Secret 2 - Dragon Coins"
|
||||
donut_ghost_house_exit_1 = "Donut Ghost House - Normal Exit"
|
||||
donut_ghost_house_exit_2 = "Donut Ghost House - Secret Exit"
|
||||
donut_secret_house_exit_1 = "Donut Secret House - Normal Exit"
|
||||
donut_secret_house_exit_2 = "Donut Secret House - Secret Exit"
|
||||
donut_plains_castle = "#2 Morton's Castle - Normal Exit"
|
||||
donut_plains_koopaling = "#2 Morton's Castle - Boss"
|
||||
|
||||
green_switch_palace = "Green Switch Palace"
|
||||
|
||||
vanilla_dome_1_exit_1 = "Vanilla Dome 1 - Normal Exit"
|
||||
vanilla_dome_1_exit_2 = "Vanilla Dome 1 - Secret Exit"
|
||||
vanilla_dome_1_dragon = "Vanilla Dome 1 - Dragon Coins"
|
||||
vanilla_dome_2_exit_1 = "Vanilla Dome 2 - Normal Exit"
|
||||
vanilla_dome_2_exit_2 = "Vanilla Dome 2 - Secret Exit"
|
||||
vanilla_dome_2_dragon = "Vanilla Dome 2 - Dragon Coins"
|
||||
vanilla_dome_3_exit_1 = "Vanilla Dome 3 - Normal Exit"
|
||||
vanilla_dome_3_dragon = "Vanilla Dome 3 - Dragon Coins"
|
||||
vanilla_dome_4_exit_1 = "Vanilla Dome 4 - Normal Exit"
|
||||
vanilla_dome_4_dragon = "Vanilla Dome 4 - Dragon Coins"
|
||||
vanilla_secret_1_exit_1 = "Vanilla Secret 1 - Normal Exit"
|
||||
vanilla_secret_1_exit_2 = "Vanilla Secret 1 - Secret Exit"
|
||||
vanilla_secret_1_dragon = "Vanilla Secret 1 - Dragon Coins"
|
||||
vanilla_secret_2_exit_1 = "Vanilla Secret 2 - Normal Exit"
|
||||
vanilla_secret_2_dragon = "Vanilla Secret 2 - Dragon Coins"
|
||||
vanilla_secret_3_exit_1 = "Vanilla Secret 3 - Normal Exit"
|
||||
vanilla_secret_3_dragon = "Vanilla Secret 3 - Dragon Coins"
|
||||
vanilla_ghost_house_exit_1 = "Vanilla Ghost House - Normal Exit"
|
||||
vanilla_ghost_house_dragon = "Vanilla Ghost House - Dragon Coins"
|
||||
vanilla_fortress = "Vanilla Fortress - Normal Exit"
|
||||
vanilla_reznor = "Vanilla Fortress - Boss"
|
||||
vanilla_dome_castle = "#3 Lemmy's Castle - Normal Exit"
|
||||
vanilla_dome_koopaling = "#3 Lemmy's Castle - Boss"
|
||||
|
||||
red_switch_palace = "Red Switch Palace"
|
||||
|
||||
butter_bridge_1_exit_1 = "Butter Bridge 1 - Normal Exit"
|
||||
butter_bridge_1_dragon = "Butter Bridge 1 - Dragon Coins"
|
||||
butter_bridge_2_exit_1 = "Butter Bridge 2 - Normal Exit"
|
||||
butter_bridge_2_dragon = "Butter Bridge 2 - Dragon Coins"
|
||||
cheese_bridge_exit_1 = "Cheese Bridge - Normal Exit"
|
||||
cheese_bridge_exit_2 = "Cheese Bridge - Secret Exit"
|
||||
cheese_bridge_dragon = "Cheese Bridge - Dragon Coins"
|
||||
cookie_mountain_exit_1 = "Cookie Mountain - Normal Exit"
|
||||
cookie_mountain_dragon = "Cookie Mountain - Dragon Coins"
|
||||
soda_lake_exit_1 = "Soda Lake - Normal Exit"
|
||||
soda_lake_dragon = "Soda Lake - Dragon Coins"
|
||||
twin_bridges_castle = "#4 Ludwig's Castle - Normal Exit"
|
||||
twin_bridges_koopaling = "#4 Ludwig's Castle - Boss"
|
||||
|
||||
forest_of_illusion_1_exit_1 = "Forest of Illusion 1 - Normal Exit"
|
||||
forest_of_illusion_1_exit_2 = "Forest of Illusion 1 - Secret Exit"
|
||||
forest_of_illusion_2_exit_1 = "Forest of Illusion 2 - Normal Exit"
|
||||
forest_of_illusion_2_exit_2 = "Forest of Illusion 2 - Secret Exit"
|
||||
forest_of_illusion_2_dragon = "Forest of Illusion 2 - Dragon Coins"
|
||||
forest_of_illusion_3_exit_1 = "Forest of Illusion 3 - Normal Exit"
|
||||
forest_of_illusion_3_exit_2 = "Forest of Illusion 3 - Secret Exit"
|
||||
forest_of_illusion_3_dragon = "Forest of Illusion 3 - Dragon Coins"
|
||||
forest_of_illusion_4_exit_1 = "Forest of Illusion 4 - Normal Exit"
|
||||
forest_of_illusion_4_exit_2 = "Forest of Illusion 4 - Secret Exit"
|
||||
forest_of_illusion_4_dragon = "Forest of Illusion 4 - Dragon Coins"
|
||||
forest_ghost_house_exit_1 = "Forest Ghost House - Normal Exit"
|
||||
forest_ghost_house_exit_2 = "Forest Ghost House - Secret Exit"
|
||||
forest_ghost_house_dragon = "Forest Ghost House - Dragon Coins"
|
||||
forest_secret_exit_1 = "Forest Secret - Normal Exit"
|
||||
forest_secret_dragon = "Forest Secret - Dragon Coins"
|
||||
forest_fortress = "Forest Fortress - Normal Exit"
|
||||
forest_reznor = "Forest Fortress - Boss"
|
||||
forest_castle = "#5 Roy's Castle - Normal Exit"
|
||||
forest_castle_dragon = "#5 Roy's Castle - Dragon Coins"
|
||||
forest_koopaling = "#5 Roy's Castle - Boss"
|
||||
|
||||
blue_switch_palace = "Blue Switch Palace"
|
||||
|
||||
chocolate_island_1_exit_1 = "Chocolate Island 1 - Normal Exit"
|
||||
chocolate_island_1_dragon = "Chocolate Island 1 - Dragon Coins"
|
||||
chocolate_island_2_exit_1 = "Chocolate Island 2 - Normal Exit"
|
||||
chocolate_island_2_exit_2 = "Chocolate Island 2 - Secret Exit"
|
||||
chocolate_island_2_dragon = "Chocolate Island 2 - Dragon Coins"
|
||||
chocolate_island_3_exit_1 = "Chocolate Island 3 - Normal Exit"
|
||||
chocolate_island_3_exit_2 = "Chocolate Island 3 - Secret Exit"
|
||||
chocolate_island_3_dragon = "Chocolate Island 3 - Dragon Coins"
|
||||
chocolate_island_4_exit_1 = "Chocolate Island 4 - Normal Exit"
|
||||
chocolate_island_4_dragon = "Chocolate Island 4 - Dragon Coins"
|
||||
chocolate_island_5_exit_1 = "Chocolate Island 5 - Normal Exit"
|
||||
chocolate_island_5_dragon = "Chocolate Island 5 - Dragon Coins"
|
||||
chocolate_ghost_house_exit_1 = "Choco-Ghost House - Normal Exit"
|
||||
chocolate_secret_exit_1 = "Chocolate Secret - Normal Exit"
|
||||
chocolate_fortress = "Chocolate Fortress - Normal Exit"
|
||||
chocolate_reznor = "Chocolate Fortress Defeat"
|
||||
chocolate_castle = "#6 Wendy's Castle - Normal Exit"
|
||||
chocolate_koopaling = "#6 Wendy's Castle - Boss"
|
||||
|
||||
sunken_ghost_ship = "Sunken Ghost Ship - Normal Exit"
|
||||
sunken_ghost_ship_dragon = "Sunken Ghost Ship - Dragon Coins"
|
||||
|
||||
valley_of_bowser_1_exit_1 = "Valley of Bowser 1 - Normal Exit"
|
||||
valley_of_bowser_1_dragon = "Valley of Bowser 1 - Dragon Coins"
|
||||
valley_of_bowser_2_exit_1 = "Valley of Bowser 2 - Normal Exit"
|
||||
valley_of_bowser_2_exit_2 = "Valley of Bowser 2 - Secret Exit"
|
||||
valley_of_bowser_2_dragon = "Valley of Bowser 2 - Dragon Coins"
|
||||
valley_of_bowser_3_exit_1 = "Valley of Bowser 3 - Normal Exit"
|
||||
valley_of_bowser_3_dragon = "Valley of Bowser 3 - Dragon Coins"
|
||||
valley_of_bowser_4_exit_1 = "Valley of Bowser 4 - Normal Exit"
|
||||
valley_of_bowser_4_exit_2 = "Valley of Bowser 4 - Secret Exit"
|
||||
valley_ghost_house_exit_1 = "Valley Ghost House - Normal Exit"
|
||||
valley_ghost_house_exit_2 = "Valley Ghost House - Secret Exit"
|
||||
valley_ghost_house_dragon = "Valley Ghost House - Dragon Coins"
|
||||
valley_fortress = "Valley Fortress - Normal Exit"
|
||||
valley_reznor = "Valley Fortress - Boss"
|
||||
valley_castle = "#7 Larry's Castle - Normal Exit"
|
||||
valley_castle_dragon = "#7 Larry's Castle - Dragon Coins"
|
||||
valley_koopaling = "#7 Larry's Castle - Boss"
|
||||
|
||||
front_door = "Front Door"
|
||||
back_door = "Back Door"
|
||||
bowser = "Bowser"
|
||||
|
||||
star_road_1_exit_1 = "Star Road 1 - Normal Exit"
|
||||
star_road_1_exit_2 = "Star Road 1 - Secret Exit"
|
||||
star_road_1_dragon = "Star Road 1 - Dragon Coins"
|
||||
star_road_2_exit_1 = "Star Road 2 - Normal Exit"
|
||||
star_road_2_exit_2 = "Star Road 2 - Secret Exit"
|
||||
star_road_3_exit_1 = "Star Road 3 - Normal Exit"
|
||||
star_road_3_exit_2 = "Star Road 3 - Secret Exit"
|
||||
star_road_4_exit_1 = "Star Road 4 - Normal Exit"
|
||||
star_road_4_exit_2 = "Star Road 4 - Secret Exit"
|
||||
star_road_5_exit_1 = "Star Road 5 - Normal Exit"
|
||||
star_road_5_exit_2 = "Star Road 5 - Secret Exit"
|
||||
|
||||
special_zone_1_exit_1 = "Gnarly - Normal Exit"
|
||||
special_zone_1_dragon = "Gnarly - Dragon Coins"
|
||||
special_zone_2_exit_1 = "Tubular - Normal Exit"
|
||||
special_zone_2_dragon = "Tubular - Dragon Coins"
|
||||
special_zone_3_exit_1 = "Way Cool - Normal Exit"
|
||||
special_zone_3_dragon = "Way Cool - Dragon Coins"
|
||||
special_zone_4_exit_1 = "Awesome - Normal Exit"
|
||||
special_zone_4_dragon = "Awesome - Dragon Coins"
|
||||
special_zone_5_exit_1 = "Groovy - Normal Exit"
|
||||
special_zone_5_dragon = "Groovy - Dragon Coins"
|
||||
special_zone_6_exit_1 = "Mondo - Normal Exit"
|
||||
special_zone_6_dragon = "Mondo - Dragon Coins"
|
||||
special_zone_7_exit_1 = "Outrageous - Normal Exit"
|
||||
special_zone_7_dragon = "Outrageous - Dragon Coins"
|
||||
special_zone_8_exit_1 = "Funky - Normal Exit"
|
||||
special_zone_8_dragon = "Funky - Dragon Coins"
|
||||
|
||||
|
||||
# Region Definitions
|
||||
menu_region = "Menu"
|
||||
|
||||
yoshis_island_region = "Yoshi's Island"
|
||||
donut_plains_region = "Donut Plains"
|
||||
vanilla_dome_region = "Vanilla Dome"
|
||||
twin_bridges_region = "Twin Bridges"
|
||||
forest_of_illusion_region = "Forest of Illusion"
|
||||
chocolate_island_region = "Chocolate Island"
|
||||
valley_of_bowser_region = "Valley of Bowser"
|
||||
star_road_region = "Star Road"
|
||||
special_zone_region = "Special Zone"
|
||||
|
||||
yoshis_island_1_tile = "Yoshi's Island 1 - Tile"
|
||||
yoshis_island_1_region = "Yoshi's Island 1"
|
||||
yoshis_island_2_tile = "Yoshi's Island 2 - Tile"
|
||||
yoshis_island_2_region = "Yoshi's Island 2"
|
||||
yoshis_island_3_tile = "Yoshi's Island 3 - Tile"
|
||||
yoshis_island_3_region = "Yoshi's Island 3"
|
||||
yoshis_island_4_tile = "Yoshi's Island 4 - Tile"
|
||||
yoshis_island_4_region = "Yoshi's Island 4"
|
||||
yoshis_island_castle_tile = "#1 Iggy's Castle - Tile"
|
||||
yoshis_island_castle_region = "#1 Iggy's Castle"
|
||||
|
||||
yellow_switch_palace_tile = "Yellow Switch Palace - Tile"
|
||||
|
||||
donut_plains_1_tile = "Donut Plains 1 - Tile"
|
||||
donut_plains_1_region = "Donut Plains 1"
|
||||
donut_plains_2_tile = "Donut Plains 2 - Tile"
|
||||
donut_plains_2_region = "Donut Plains 2"
|
||||
donut_plains_3_tile = "Donut Plains 3 - Tile"
|
||||
donut_plains_3_region = "Donut Plains 3"
|
||||
donut_plains_4_tile = "Donut Plains 4 - Tile"
|
||||
donut_plains_4_region = "Donut Plains 4"
|
||||
donut_secret_1_tile = "Donut Secret 1 - Tile"
|
||||
donut_secret_1_region = "Donut Secret 1"
|
||||
donut_secret_2_tile = "Donut Secret 2 - Tile"
|
||||
donut_secret_2_region = "Donut Secret 2"
|
||||
donut_ghost_house_tile = "Donut Ghost House - Tile"
|
||||
donut_ghost_house_region = "Donut Ghost House"
|
||||
donut_secret_house_tile = "Donut Secret House - Tile"
|
||||
donut_secret_house_region = "Donut Secret House"
|
||||
donut_plains_castle_tile = "#2 Morton's Castle - Tile"
|
||||
donut_plains_castle_region = "#2 Morton's Castle"
|
||||
donut_plains_top_secret = "Top Secret Area"
|
||||
donut_plains_top_secret_tile = "Top Secret Area - Tile"
|
||||
donut_plains_star_road = "Donut Plains - Star Road"
|
||||
|
||||
green_switch_palace_tile = "Green Switch Palace - Tile"
|
||||
|
||||
vanilla_dome_1_tile = "Vanilla Dome 1 - Tile"
|
||||
vanilla_dome_1_region = "Vanilla Dome 1"
|
||||
vanilla_dome_2_tile = "Vanilla Dome 2 - Tile"
|
||||
vanilla_dome_2_region = "Vanilla Dome 2"
|
||||
vanilla_dome_3_tile = "Vanilla Dome 3 - Tile"
|
||||
vanilla_dome_3_region = "Vanilla Dome 3"
|
||||
vanilla_dome_4_tile = "Vanilla Dome 4 - Tile"
|
||||
vanilla_dome_4_region = "Vanilla Dome 4"
|
||||
vanilla_secret_1_tile = "Vanilla Secret 1 - Tile"
|
||||
vanilla_secret_1_region = "Vanilla Secret 1"
|
||||
vanilla_secret_2_tile = "Vanilla Secret 2 - Tile"
|
||||
vanilla_secret_2_region = "Vanilla Secret 2"
|
||||
vanilla_secret_3_tile = "Vanilla Secret 3 - Tile"
|
||||
vanilla_secret_3_region = "Vanilla Secret 3"
|
||||
vanilla_ghost_house_tile = "Vanilla Ghost House - Tile"
|
||||
vanilla_ghost_house_region = "Vanilla Ghost House"
|
||||
vanilla_fortress_tile = "Vanilla Fortress - Tile"
|
||||
vanilla_fortress_region = "Vanilla Fortress"
|
||||
vanilla_dome_castle_tile = "#3 Lemmy's Castle - Tile"
|
||||
vanilla_dome_castle_region = "#3 Lemmy's Castle"
|
||||
vanilla_dome_star_road = "Vanilla Dome - Star Road"
|
||||
|
||||
red_switch_palace_tile = "Red Switch Palace - Tile"
|
||||
|
||||
butter_bridge_1_tile = "Butter Bridge 1 - Tile"
|
||||
butter_bridge_1_region = "Butter Bridge 1"
|
||||
butter_bridge_2_tile = "Butter Bridge 2 - Tile"
|
||||
butter_bridge_2_region = "Butter Bridge 2"
|
||||
cheese_bridge_tile = "Cheese Bridge - Tile"
|
||||
cheese_bridge_region = "Cheese Bridge"
|
||||
cookie_mountain_tile = "Cookie Mountain - Tile"
|
||||
cookie_mountain_region = "Cookie Mountain"
|
||||
soda_lake_tile = "Soda Lake - Tile"
|
||||
soda_lake_region = "Soda Lake"
|
||||
twin_bridges_castle_tile = "#4 Ludwig's Castle - Tile"
|
||||
twin_bridges_castle_region = "#4 Ludwig's Castle"
|
||||
twin_bridges_star_road = "Twin Bridges - Star Road"
|
||||
|
||||
forest_of_illusion_1_tile = "Forest of Illusion 1 - Tile"
|
||||
forest_of_illusion_1_region = "Forest of Illusion 1"
|
||||
forest_of_illusion_2_tile = "Forest of Illusion 2 - Tile"
|
||||
forest_of_illusion_2_region = "Forest of Illusion 2"
|
||||
forest_of_illusion_3_tile = "Forest of Illusion 3 - Tile"
|
||||
forest_of_illusion_3_region = "Forest of Illusion 3"
|
||||
forest_of_illusion_4_tile = "Forest of Illusion 4 - Tile"
|
||||
forest_of_illusion_4_region = "Forest of Illusion 4"
|
||||
forest_ghost_house_tile = "Forest Ghost House - Tile"
|
||||
forest_ghost_house_region = "Forest Ghost House"
|
||||
forest_secret_tile = "Forest Secret - Tile"
|
||||
forest_secret_region = "Forest Secret"
|
||||
forest_fortress_tile = "Forest Fortress - Tile"
|
||||
forest_fortress_region = "Forest Fortress"
|
||||
forest_castle_tile = "#5 Roy's Castle - Tile"
|
||||
forest_castle_region = "#5 Roy's Castle"
|
||||
forest_star_road = "Forest of Illusion - Star Road"
|
||||
|
||||
blue_switch_palace_tile = "Blue Switch Palace - Tile"
|
||||
|
||||
chocolate_island_1_tile = "Chocolate Island 1 - Tile"
|
||||
chocolate_island_1_region = "Chocolate Island 1"
|
||||
chocolate_island_2_tile = "Chocolate Island 2 - Tile"
|
||||
chocolate_island_2_region = "Chocolate Island 2"
|
||||
chocolate_island_3_tile = "Chocolate Island 3 - Tile"
|
||||
chocolate_island_3_region = "Chocolate Island 3"
|
||||
chocolate_island_4_tile = "Chocolate Island 4 - Tile"
|
||||
chocolate_island_4_region = "Chocolate Island 4"
|
||||
chocolate_island_5_tile = "Chocolate Island 5 - Tile"
|
||||
chocolate_island_5_region = "Chocolate Island 5"
|
||||
chocolate_ghost_house_tile = "Choco-Ghost House - Tile"
|
||||
chocolate_ghost_house_region = "Choco-Ghost House"
|
||||
chocolate_secret_tile = "Chocolate Secret - Tile"
|
||||
chocolate_secret_region = "Chocolate Secret"
|
||||
chocolate_fortress_tile = "Chocolate Fortress - Tile"
|
||||
chocolate_fortress_region = "Chocolate Fortress"
|
||||
chocolate_castle_tile = "#6 Wendy's Castle - Tile"
|
||||
chocolate_castle_region = "#6 Wendy's Castle"
|
||||
|
||||
sunken_ghost_ship_tile = "Sunken Ghost Ship - Tile"
|
||||
sunken_ghost_ship_region = "Sunken Ghost Ship"
|
||||
|
||||
valley_of_bowser_1_tile = "Valley of Bowser 1 - Tile"
|
||||
valley_of_bowser_1_region = "Valley of Bowser 1"
|
||||
valley_of_bowser_2_tile = "Valley of Bowser 2 - Tile"
|
||||
valley_of_bowser_2_region = "Valley of Bowser 2"
|
||||
valley_of_bowser_3_tile = "Valley of Bowser 3 - Tile"
|
||||
valley_of_bowser_3_region = "Valley of Bowser 3"
|
||||
valley_of_bowser_4_tile = "Valley of Bowser 4 - Tile"
|
||||
valley_of_bowser_4_region = "Valley of Bowser 4"
|
||||
valley_ghost_house_tile = "Valley Ghost House - Tile"
|
||||
valley_ghost_house_region = "Valley Ghost House"
|
||||
valley_fortress_tile = "Valley Fortress - Tile"
|
||||
valley_fortress_region = "Valley Fortress"
|
||||
valley_castle_tile = "#7 Larry's Castle - Tile"
|
||||
valley_castle_region = "#7 Larry's Castle"
|
||||
valley_star_road = "Valley of Bowser - Star Road"
|
||||
|
||||
front_door_tile = "Front Door - Tile"
|
||||
back_door_tile = "Back Door - Tile"
|
||||
bowser_region = "Bowser - Region"
|
||||
|
||||
star_road_donut = "Star Road - Donut Plains"
|
||||
star_road_1_tile = "Star Road 1 - Tile"
|
||||
star_road_1_region = "Star Road 1"
|
||||
star_road_vanilla = "Star Road - Vanilla Dome"
|
||||
star_road_2_tile = "Star Road 2 - Tile"
|
||||
star_road_2_region = "Star Road 2"
|
||||
star_road_twin_bridges = "Star Road - Twin Bridges"
|
||||
star_road_3_tile = "Star Road 3 - Tile"
|
||||
star_road_3_region = "Star Road 3"
|
||||
star_road_forest = "Star Road - Forest of Illusion"
|
||||
star_road_4_tile = "Star Road 4 - Tile"
|
||||
star_road_4_region = "Star Road 4"
|
||||
star_road_valley = "Star Road - Valley of Bowser"
|
||||
star_road_5_tile = "Star Road 5 - Tile"
|
||||
star_road_5_region = "Star Road 5"
|
||||
star_road_special = "Star Road - Special Zone"
|
||||
|
||||
special_star_road = "Special Zone - Star Road"
|
||||
special_zone_1_tile = "Gnarly - Tile"
|
||||
special_zone_1_region = "Gnarly"
|
||||
special_zone_2_tile = "Tubular - Tile"
|
||||
special_zone_2_region = "Tubular"
|
||||
special_zone_3_tile = "Way Cool - Tile"
|
||||
special_zone_3_region = "Way Cool"
|
||||
special_zone_4_tile = "Awesome - Tile"
|
||||
special_zone_4_region = "Awesome"
|
||||
special_zone_5_tile = "Groovy - Tile"
|
||||
special_zone_5_region = "Groovy"
|
||||
special_zone_6_tile = "Mondo - Tile"
|
||||
special_zone_6_region = "Mondo"
|
||||
special_zone_7_tile = "Outrageous - Tile"
|
||||
special_zone_7_region = "Outrageous"
|
||||
special_zone_8_tile = "Funky - Tile"
|
||||
special_zone_8_region = "Funky"
|
||||
special_complete = "Special Zone - Star Road - Complete"
|
||||
140
worlds/smw/Names/TextBox.py
Normal file
140
worlds/smw/Names/TextBox.py
Normal file
@@ -0,0 +1,140 @@
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
|
||||
import math
|
||||
|
||||
|
||||
text_mapping = {
|
||||
"A": 0x00, "B": 0x01, "C": 0x02, "D": 0x03, "E": 0x04, "F": 0x05, "G": 0x06, "H": 0x07, "I": 0x08, "J": 0x09,
|
||||
"K": 0x0A, "L": 0x0B, "M": 0x0C, "N": 0x0D, "O": 0x0E, "P": 0x0F, "Q": 0x10, "R": 0x11, "S": 0x12, "T": 0x13,
|
||||
"U": 0x14, "V": 0x15, "W": 0x16, "X": 0x17, "Y": 0x18, "Z": 0x19,
|
||||
|
||||
"!": 0x1A, ".": 0x1B, "-": 0x1C, ",": 0x1D, "?": 0x1E, " ": 0x1F,
|
||||
|
||||
"0": 0x22, "1": 0x23, "2": 0x24, "3": 0x25, "4": 0x26, "5": 0x27, "6": 0x28, "7": 0x29, "8": 0x2A, "9": 0x2B,
|
||||
|
||||
"a": 0x40, "b": 0x41, "c": 0x42, "d": 0x43, "e": 0x44, "f": 0x45, "g": 0x46, "h": 0x47, "i": 0x48, "j": 0x49,
|
||||
"k": 0x4A, "l": 0x4B, "m": 0x4C, "n": 0x4D, "o": 0x4E, "p": 0x4F, "q": 0x50, "r": 0x51, "s": 0x52, "t": 0x53,
|
||||
"u": 0x54, "v": 0x55, "w": 0x56, "x": 0x57, "y": 0x58, "z": 0x59,
|
||||
|
||||
"#": 0x5A, "(": 0x5B, ")": 0x5C, "'": 0x5D
|
||||
}
|
||||
|
||||
title_text_mapping = {
|
||||
"A": [0x0A, 0x38], "B": [0x0B, 0x38], "C": [0x0C, 0x38], "D": [0x0D, 0x38], "E": [0x0E, 0x38],
|
||||
"F": [0x0F, 0x38], "G": [0x10, 0x38], "H": [0x11, 0x38], "I": [0x12, 0x38], "J": [0x13, 0x38],
|
||||
"K": [0x14, 0x38], "L": [0x15, 0x38], "M": [0x16, 0x38], "N": [0x17, 0x38], "O": [0x18, 0x38],
|
||||
"P": [0x19, 0x38], "Q": [0x1A, 0x38], "R": [0x1B, 0x38], "S": [0x1C, 0x38], "T": [0x1D, 0x38],
|
||||
"U": [0x1E, 0x38], "V": [0x1F, 0x38], "W": [0x20, 0x38], "X": [0x21, 0x38], "Y": [0x22, 0x38],
|
||||
"Z": [0x23, 0x38], " ": [0xFC, 0x38], ".": [0x24, 0x38],
|
||||
"0": [0x00, 0x38], "1": [0x01, 0x38], "2": [0x02, 0x38], "3": [0x03, 0x38], "4": [0x04, 0x38],
|
||||
"5": [0x05, 0x38], "6": [0x06, 0x38], "7": [0x07, 0x38], "8": [0x08, 0x38], "9": [0x09, 0x38],
|
||||
}
|
||||
|
||||
|
||||
def string_to_bytes(input_string):
|
||||
out_array = bytearray()
|
||||
for letter in input_string:
|
||||
out_array.append(text_mapping[letter] if letter in text_mapping else text_mapping["."])
|
||||
|
||||
return out_array
|
||||
|
||||
|
||||
def generate_text_box(input_string):
|
||||
out_bytes = bytearray()
|
||||
box_line_count = 0
|
||||
box_line_chr_count = 0
|
||||
for word in input_string.split():
|
||||
if box_line_chr_count + len(word) > 18:
|
||||
out_bytes[-1] += 0x80
|
||||
box_line_count += 1
|
||||
box_line_chr_count = 0
|
||||
|
||||
out_bytes.extend(string_to_bytes(word))
|
||||
box_line_chr_count += len(word)
|
||||
|
||||
if box_line_chr_count < 18:
|
||||
box_line_chr_count += 1
|
||||
out_bytes.append(0x1F)
|
||||
|
||||
for i in range(box_line_count, 8):
|
||||
out_bytes.append(0x9F)
|
||||
|
||||
return out_bytes
|
||||
|
||||
|
||||
def generate_goal_text(world: MultiWorld, player: int):
|
||||
out_array = bytearray()
|
||||
if world.goal[player] == "yoshi_egg_hunt":
|
||||
required_yoshi_eggs = max(math.floor(
|
||||
world.number_of_yoshi_eggs[player].value * (world.percentage_of_yoshi_eggs[player].value / 100.0)), 1)
|
||||
out_array += bytearray([0x9F, 0x9F])
|
||||
out_array += string_to_bytes(" You must acquire")
|
||||
out_array[-1] += 0x80
|
||||
out_array += string_to_bytes(f' {required_yoshi_eggs:02} Yoshi Eggs,')
|
||||
out_array[-1] += 0x80
|
||||
out_array += string_to_bytes("then return here.")
|
||||
out_array[-1] += 0x80
|
||||
out_array += bytearray([0x9F, 0x9F, 0x9F])
|
||||
else:
|
||||
bosses_required = world.bosses_required[player].value
|
||||
out_array += bytearray([0x9F, 0x9F])
|
||||
out_array += string_to_bytes(" You must defeat")
|
||||
out_array[-1] += 0x80
|
||||
out_array += string_to_bytes(f' {bosses_required:02} Bosses,')
|
||||
out_array[-1] += 0x80
|
||||
out_array += string_to_bytes("then defeat Bowser")
|
||||
out_array[-1] += 0x80
|
||||
out_array += bytearray([0x9F, 0x9F, 0x9F])
|
||||
|
||||
return out_array
|
||||
|
||||
|
||||
def generate_received_text(item_name: str, player_name: str):
|
||||
out_array = bytearray()
|
||||
|
||||
item_name = item_name[:18]
|
||||
player_name = player_name[:18]
|
||||
|
||||
item_buffer = max(0, math.floor((18 - len(item_name)) / 2))
|
||||
player_buffer = max(0, math.floor((18 - len(player_name)) / 2))
|
||||
|
||||
out_array += bytearray([0x9F, 0x9F])
|
||||
out_array += string_to_bytes(" Received")
|
||||
out_array[-1] += 0x80
|
||||
out_array += bytearray([0x1F] * item_buffer)
|
||||
out_array += string_to_bytes(item_name)
|
||||
out_array[-1] += 0x80
|
||||
out_array += string_to_bytes(" from")
|
||||
out_array[-1] += 0x80
|
||||
out_array += bytearray([0x1F] * player_buffer)
|
||||
out_array += string_to_bytes(player_name)
|
||||
out_array[-1] += 0x80
|
||||
out_array += bytearray([0x9F, 0x9F])
|
||||
|
||||
return out_array
|
||||
|
||||
|
||||
def generate_sent_text(item_name: str, player_name: str):
|
||||
out_array = bytearray()
|
||||
|
||||
item_name = item_name[:18]
|
||||
player_name = player_name[:18]
|
||||
|
||||
item_buffer = max(0, math.floor((18 - len(item_name)) / 2))
|
||||
player_buffer = max(0, math.floor((18 - len(player_name)) / 2))
|
||||
|
||||
out_array += bytearray([0x9F, 0x9F])
|
||||
out_array += string_to_bytes(" Sent")
|
||||
out_array[-1] += 0x80
|
||||
out_array += bytearray([0x1F] * item_buffer)
|
||||
out_array += string_to_bytes(item_name)
|
||||
out_array[-1] += 0x80
|
||||
out_array += string_to_bytes(" to")
|
||||
out_array[-1] += 0x80
|
||||
out_array += bytearray([0x1F] * player_buffer)
|
||||
out_array += string_to_bytes(player_name)
|
||||
out_array[-1] += 0x80
|
||||
out_array += bytearray([0x9F, 0x9F])
|
||||
|
||||
return out_array
|
||||
236
worlds/smw/Options.py
Normal file
236
worlds/smw/Options.py
Normal file
@@ -0,0 +1,236 @@
|
||||
import typing
|
||||
|
||||
from Options import Choice, Range, Option, Toggle, DeathLink, DefaultOnToggle, OptionList
|
||||
|
||||
|
||||
class Goal(Choice):
|
||||
"""
|
||||
Determines the goal of the seed
|
||||
Bowser: Defeat Koopalings, reach Bowser's Castle and defeat Bowser
|
||||
Yoshi Egg Hunt: Find a certain number of Yoshi Eggs
|
||||
"""
|
||||
display_name = "Goal"
|
||||
option_bowser = 0
|
||||
option_yoshi_egg_hunt = 1
|
||||
default = 0
|
||||
|
||||
|
||||
class BossesRequired(Range):
|
||||
"""
|
||||
How many Bosses (Koopalings or Reznor) must be defeated in order to defeat Bowser
|
||||
"""
|
||||
display_name = "Bosses Required"
|
||||
range_start = 0
|
||||
range_end = 11
|
||||
default = 7
|
||||
|
||||
|
||||
class NumberOfYoshiEggs(Range):
|
||||
"""
|
||||
How many Yoshi Eggs are in the pool for Yoshi Egg Hunt
|
||||
"""
|
||||
display_name = "Total Number of Yoshi Eggs"
|
||||
range_start = 1
|
||||
range_end = 80
|
||||
default = 50
|
||||
|
||||
|
||||
class PercentageOfYoshiEggs(Range):
|
||||
"""
|
||||
What Percentage of Yoshi Eggs are required to finish Yoshi Egg Hunt
|
||||
"""
|
||||
display_name = "Required Percentage of Yoshi Eggs"
|
||||
range_start = 1
|
||||
range_end = 100
|
||||
default = 100
|
||||
|
||||
|
||||
class DragonCoinChecks(Toggle):
|
||||
"""
|
||||
Whether collecting 5 Dragon Coins in each level will grant a check
|
||||
"""
|
||||
display_name = "Dragon Coin Checks"
|
||||
|
||||
|
||||
class BowserCastleDoors(Choice):
|
||||
"""
|
||||
How the doors of Bowser's Castle behave
|
||||
Vanilla: Front and Back Doors behave as vanilla
|
||||
Fast: Both doors behave as the Back Door
|
||||
Slow: Both doors behave as the Front Door
|
||||
"Front Door" requires beating all 8 Rooms
|
||||
"Back Door" only requires going through the dark hallway to Bowser
|
||||
"""
|
||||
display_name = "Bowser Castle Doors"
|
||||
option_vanilla = 0
|
||||
option_fast = 1
|
||||
option_slow = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class LevelShuffle(Toggle):
|
||||
"""
|
||||
Whether levels are shuffled
|
||||
"""
|
||||
display_name = "Level Shuffle"
|
||||
|
||||
|
||||
class SwapDonutGhostHouseExits(Toggle):
|
||||
"""
|
||||
If enabled, this option will swap which overworld direction the two exits of the level at the Donut Ghost House overworld tile go:
|
||||
False: Normal Exit goes up, Secret Exit goes right.
|
||||
True: Normal Exit goes right, Secret Exit goes up.
|
||||
"""
|
||||
display_name = "Swap Donut GH Exits"
|
||||
|
||||
|
||||
class DisplaySentItemPopups(Choice):
|
||||
"""
|
||||
What messages to display in-game for items sent
|
||||
"""
|
||||
display_name = "Display Sent Item Popups"
|
||||
option_none = 0
|
||||
option_all = 1
|
||||
default = 1
|
||||
|
||||
|
||||
class DisplayReceivedItemPopups(Choice):
|
||||
"""
|
||||
What messages to display in-game for items received
|
||||
"""
|
||||
display_name = "Display Received Item Popups"
|
||||
option_none = 0
|
||||
option_all = 1
|
||||
option_progression = 2
|
||||
default = 2
|
||||
|
||||
|
||||
class TrapFillPercentage(Range):
|
||||
"""
|
||||
Replace a percentage of junk items in the item pool with random traps
|
||||
"""
|
||||
display_name = "Trap Fill Percentage"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 0
|
||||
|
||||
|
||||
class BaseTrapWeight(Choice):
|
||||
"""
|
||||
Base Class for Trap Weights
|
||||
"""
|
||||
option_none = 0
|
||||
option_low = 1
|
||||
option_medium = 2
|
||||
option_high = 4
|
||||
default = 2
|
||||
|
||||
|
||||
class IceTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of a receiving a trap which causes the level to become slippery
|
||||
"""
|
||||
display_name = "Ice Trap Weight"
|
||||
|
||||
|
||||
class StunTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of a receiving a trap which briefly stuns Mario
|
||||
"""
|
||||
display_name = "Stun Trap Weight"
|
||||
|
||||
|
||||
class LiteratureTrapWeight(BaseTrapWeight):
|
||||
"""
|
||||
Likelihood of a receiving a trap which causes the player to read literature
|
||||
"""
|
||||
display_name = "Literature Trap Weight"
|
||||
|
||||
|
||||
class Autosave(DefaultOnToggle):
|
||||
"""
|
||||
Whether a save prompt will appear after every level
|
||||
"""
|
||||
display_name = "Autosave"
|
||||
|
||||
|
||||
class MusicShuffle(Choice):
|
||||
"""
|
||||
Music shuffle type
|
||||
None: No Music is shuffled
|
||||
Consistent: Each music track is consistently shuffled throughout the game
|
||||
Full: Each individual level has a random music track
|
||||
Singularity: The entire game uses one song for overworld and one song for levels
|
||||
"""
|
||||
display_name = "Music Shuffle"
|
||||
option_none = 0
|
||||
option_consistent = 1
|
||||
option_full = 2
|
||||
option_singularity = 3
|
||||
default = 0
|
||||
|
||||
|
||||
class MarioPalette(Choice):
|
||||
"""
|
||||
Mario palette color
|
||||
"""
|
||||
display_name = "Mario Palette"
|
||||
option_mario = 0
|
||||
option_luigi = 1
|
||||
option_wario = 2
|
||||
option_waluigi = 3
|
||||
option_geno = 4
|
||||
option_princess = 5
|
||||
option_dark = 6
|
||||
option_sponge = 7
|
||||
default = 0
|
||||
|
||||
|
||||
class ForegroundPaletteShuffle(Toggle):
|
||||
"""
|
||||
Whether to shuffle level foreground palettes
|
||||
"""
|
||||
display_name = "Foreground Palette Shuffle"
|
||||
|
||||
|
||||
class BackgroundPaletteShuffle(Toggle):
|
||||
"""
|
||||
Whether to shuffle level background palettes
|
||||
"""
|
||||
display_name = "Background Palette Shuffle"
|
||||
|
||||
|
||||
class StartingLifeCount(Range):
|
||||
"""
|
||||
How many extra lives to start the game with
|
||||
"""
|
||||
display_name = "Starting Life Count"
|
||||
range_start = 1
|
||||
range_end = 99
|
||||
default = 5
|
||||
|
||||
|
||||
|
||||
smw_options: typing.Dict[str, type(Option)] = {
|
||||
"death_link": DeathLink,
|
||||
"goal": Goal,
|
||||
"bosses_required": BossesRequired,
|
||||
"number_of_yoshi_eggs": NumberOfYoshiEggs,
|
||||
"percentage_of_yoshi_eggs": PercentageOfYoshiEggs,
|
||||
"dragon_coin_checks": DragonCoinChecks,
|
||||
"bowser_castle_doors": BowserCastleDoors,
|
||||
"level_shuffle": LevelShuffle,
|
||||
"swap_donut_gh_exits": SwapDonutGhostHouseExits,
|
||||
#"display_sent_item_popups": DisplaySentItemPopups,
|
||||
"display_received_item_popups": DisplayReceivedItemPopups,
|
||||
"trap_fill_percentage": TrapFillPercentage,
|
||||
"ice_trap_weight": IceTrapWeight,
|
||||
"stun_trap_weight": StunTrapWeight,
|
||||
"literature_trap_weight": LiteratureTrapWeight,
|
||||
"autosave": Autosave,
|
||||
"music_shuffle": MusicShuffle,
|
||||
"mario_palette": MarioPalette,
|
||||
"foreground_palette_shuffle": ForegroundPaletteShuffle,
|
||||
"background_palette_shuffle": BackgroundPaletteShuffle,
|
||||
"starting_life_count": StartingLifeCount,
|
||||
}
|
||||
1187
worlds/smw/Regions.py
Normal file
1187
worlds/smw/Regions.py
Normal file
File diff suppressed because it is too large
Load Diff
846
worlds/smw/Rom.py
Normal file
846
worlds/smw/Rom.py
Normal file
@@ -0,0 +1,846 @@
|
||||
import Utils
|
||||
from worlds.Files import APDeltaPatch
|
||||
from .Aesthetics import generate_shuffled_header_data
|
||||
from .Levels import level_info_dict
|
||||
from .Names.TextBox import generate_goal_text, title_text_mapping, generate_text_box
|
||||
|
||||
USHASH = 'cdd3c8c37322978ca8669b34bc89c804'
|
||||
ROM_PLAYER_LIMIT = 65535
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import math
|
||||
|
||||
|
||||
ability_rom_data = {
|
||||
0xBC0003: [[0x1F2C, 0x7]], # Run 0x80
|
||||
0xBC0004: [[0x1F2C, 0x6]], # Carry 0x40
|
||||
0xBC0005: [[0x1F2C, 0x2]], # Swim 0x04
|
||||
0xBC0006: [[0x1F2C, 0x3]], # Spin Jump 0x08
|
||||
0xBC0007: [[0x1F2C, 0x5]], # Climb 0x20
|
||||
0xBC0008: [[0x1F2C, 0x1]], # Yoshi 0x02
|
||||
0xBC0009: [[0x1F2C, 0x4]], # P-Switch 0x10
|
||||
#0xBC000A: [[]]
|
||||
0xBC000B: [[0x1F2D, 0x3]], # P-Balloon 0x08
|
||||
0xBC000D: [[0x1F2D, 0x4]], # Super Star 0x10
|
||||
}
|
||||
|
||||
|
||||
item_rom_data = {
|
||||
0xBC0001: [0x18E4, 0x1], # 1-Up Mushroom
|
||||
|
||||
0xBC0002: [0x1F24, 0x1, 0x1F], # Yoshi Egg
|
||||
0xBC0012: [0x1F26, 0x1, 0x09], # Boss Token
|
||||
|
||||
0xBC000E: [0x1F28, 0x1, 0x1C], # Yellow Switch Palace
|
||||
0xBC000F: [0x1F27, 0x1, 0x1C], # Green Switch Palace
|
||||
0xBC0010: [0x1F2A, 0x1, 0x1C], # Red Switch Palace
|
||||
0xBC0011: [0x1F29, 0x1, 0x1C], # Blue Switch Palace
|
||||
|
||||
0xBC0013: [0x0086, 0x1, 0x0E], # Ice Trap
|
||||
0xBC0014: [0x18BD, 0x7F, 0x18], # Stun Trap
|
||||
}
|
||||
|
||||
music_rom_data = [
|
||||
|
||||
]
|
||||
|
||||
level_music_ids = [
|
||||
|
||||
]
|
||||
|
||||
|
||||
class SMWDeltaPatch(APDeltaPatch):
|
||||
hash = USHASH
|
||||
game = "Super Mario World"
|
||||
patch_file_ending = ".apsmw"
|
||||
|
||||
@classmethod
|
||||
def get_source_data(cls) -> bytes:
|
||||
return get_base_rom_bytes()
|
||||
|
||||
|
||||
class LocalRom:
|
||||
|
||||
def __init__(self, file, patch=True, vanillaRom=None, name=None, hash=None):
|
||||
self.name = name
|
||||
self.hash = hash
|
||||
self.orig_buffer = None
|
||||
|
||||
with open(file, 'rb') as stream:
|
||||
self.buffer = Utils.read_snes_rom(stream)
|
||||
|
||||
def read_bit(self, address: int, bit_number: int) -> bool:
|
||||
bitflag = (1 << bit_number)
|
||||
return ((self.buffer[address] & bitflag) != 0)
|
||||
|
||||
def read_byte(self, address: int) -> int:
|
||||
return self.buffer[address]
|
||||
|
||||
def read_bytes(self, startaddress: int, length: int) -> bytes:
|
||||
return self.buffer[startaddress:startaddress + length]
|
||||
|
||||
def write_byte(self, address: int, value: int):
|
||||
self.buffer[address] = value
|
||||
|
||||
def write_bytes(self, startaddress: int, values):
|
||||
self.buffer[startaddress:startaddress + len(values)] = values
|
||||
|
||||
def write_to_file(self, file):
|
||||
with open(file, 'wb') as outfile:
|
||||
outfile.write(self.buffer)
|
||||
|
||||
def read_from_file(self, file):
|
||||
with open(file, 'rb') as stream:
|
||||
self.buffer = bytearray(stream.read())
|
||||
|
||||
|
||||
def handle_ability_code(rom):
|
||||
# Lock Abilities
|
||||
|
||||
#rom.write_byte(0xC581, 0x01) # No Stars
|
||||
#rom.write_byte(0x62E6, 0x01) # No Star Music
|
||||
#rom.write_byte(0xC300, 0x01) # No P-Balloons
|
||||
#rom.write_byte(0xC305, 0x01) # No P-Balloons
|
||||
|
||||
# Run
|
||||
rom.write_bytes(0x5977, bytearray([0x22, 0x10, 0xBA, 0x03])) # JSL $03BA10
|
||||
rom.write_bytes(0x597B, bytearray([0xEA] * 0x04))
|
||||
|
||||
RUN_SUB_ADDR = 0x01BA10
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x00, bytearray([0xDA])) # PHX
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x01, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x02, bytearray([0x90, 0x03])) # BCC +0x03
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x04, bytearray([0xC8])) # INY
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x05, bytearray([0xA9, 0x70])) # LDA #70
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x07, bytearray([0xAA])) # TAX
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x08, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x0B, bytearray([0x89, 0x80])) # BIT #80
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x0D, bytearray([0xF0, 0x04])) # BEQ +0x04
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x0F, bytearray([0x8A])) # TXA
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x10, bytearray([0x8D, 0xE4, 0x13])) # STA $13E4
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x13, bytearray([0x8A])) # TXA
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x14, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x15, bytearray([0xFA])) # PLX
|
||||
rom.write_bytes(RUN_SUB_ADDR + 0x16, bytearray([0x6B])) # RTL
|
||||
# End Run
|
||||
|
||||
# Purple Block Carry
|
||||
rom.write_bytes(0x726F, bytearray([0x22, 0x28, 0xBA, 0x03])) # JSL $03BA28
|
||||
rom.write_bytes(0x7273, bytearray([0xEA] * 0x02))
|
||||
|
||||
PURPLE_BLOCK_CARRY_SUB_ADDR = 0x01BA28
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x04, bytearray([0x89, 0x40])) # BIT #40
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x09, bytearray([0xAD, 0x8F, 0x14])) # LDA $148F
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x0C, bytearray([0x0D, 0x7A, 0x18])) # ORA $187A
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x0F, bytearray([0x80, 0x03])) # BRA +0x03
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x12, bytearray([0xA9, 0x01])) # LDA #01
|
||||
rom.write_bytes(PURPLE_BLOCK_CARRY_SUB_ADDR + 0x14, bytearray([0x6B])) # RTL
|
||||
# End Purple Block Carry
|
||||
|
||||
# Springboard Carry
|
||||
rom.write_bytes(0xE6DA, bytearray([0x22, 0x40, 0xBA, 0x03])) # JSL $03BA40
|
||||
rom.write_bytes(0xE6DE, bytearray([0xEA] * 0x04))
|
||||
|
||||
SPRINGBOARD_CARRY_SUB_ADDR = 0x01BA40
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x00, bytearray([0x48])) # PHA
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x01, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x05, bytearray([0x89, 0x40])) # BIT #40
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x07, bytearray([0xF0, 0x08])) # BEQ +0x08
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x09, bytearray([0xA9, 0x0B])) # LDA #0B
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x0B, bytearray([0x9D, 0xC8, 0x14])) # STA $14C8, X
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x0E, bytearray([0x9E, 0x02, 0x16])) # STZ $1602, X
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x12, bytearray([0x68])) # PLA
|
||||
rom.write_bytes(SPRINGBOARD_CARRY_SUB_ADDR + 0x13, bytearray([0x6B])) # RTL
|
||||
# End Springboard Carry
|
||||
|
||||
# Shell Carry
|
||||
rom.write_bytes(0xAA66, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(0xAA69, bytearray([0x89, 0x40])) # BIT #40
|
||||
rom.write_bytes(0xAA6B, bytearray([0xF0, 0x07])) # BEQ +0x07
|
||||
rom.write_bytes(0xAA6D, bytearray([0x22, 0x60, 0xBA, 0x03])) # JSL $03BA60
|
||||
rom.write_bytes(0xAA71, bytearray([0xEA] * 0x02))
|
||||
|
||||
SHELL_CARRY_SUB_ADDR = 0x01BA60
|
||||
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x01, bytearray([0xA9, 0x0B])) # LDA #0B
|
||||
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x03, bytearray([0x9D, 0xC8, 0x14])) # STA $14C8, X
|
||||
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x06, bytearray([0xEE, 0x70, 0x14])) # INC $1470
|
||||
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x09, bytearray([0xA9, 0x0B])) # LDA #08
|
||||
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x0B, bytearray([0x8D, 0x98, 0x14])) # STA $1498
|
||||
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x0E, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SHELL_CARRY_SUB_ADDR + 0x0F, bytearray([0x6B])) # RTL
|
||||
# End Shell Carry
|
||||
|
||||
# Yoshi Carry
|
||||
rom.write_bytes(0xF309, bytearray([0x22, 0x70, 0xBA, 0x03])) # JSL $03BA70
|
||||
rom.write_bytes(0xF30D, bytearray([0xEA] * 0x06))
|
||||
|
||||
YOSHI_CARRY_SUB_ADDR = 0x01BA70
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x04, bytearray([0x89, 0x40])) # BIT #40
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x06, bytearray([0xF0, 0x0A])) # BEQ +0x0A
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x08, bytearray([0xA9, 0x12])) # LDA #12
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x0A, bytearray([0x8D, 0xA3, 0x14])) # STA $14A3
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x0D, bytearray([0xA9, 0x21])) # LDA #21
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x0F, bytearray([0x8D, 0xFC, 0x1D])) # STA $1DFC
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x12, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(YOSHI_CARRY_SUB_ADDR + 0x13, bytearray([0x6B])) # RTL
|
||||
# End Yoshi Carry
|
||||
|
||||
# Climb
|
||||
rom.write_bytes(0x4D72, bytearray([0x5C, 0x88, 0xBA, 0x03])) # JML $03BA88
|
||||
rom.write_bytes(0x4D76, bytearray([0xEA] * 0x03))
|
||||
|
||||
CLIMB_SUB_ADDR = 0x01BA88
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x04, bytearray([0x89, 0x20])) # BIT #20
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x08, bytearray([0xA5, 0x8B])) # LDA $8B
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x0A, bytearray([0x85, 0x74])) # STA $74
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x0C, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x0D, bytearray([0x5C, 0x17, 0xDB, 0x00])) # JML $00DB17
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(CLIMB_SUB_ADDR + 0x12, bytearray([0x5C, 0x76, 0xCD, 0x00])) # JML $00CD76
|
||||
# End Climb
|
||||
|
||||
# P-Switch
|
||||
rom.write_bytes(0xAB1A, bytearray([0x22, 0xA0, 0xBA, 0x03])) # JSL $03BAA0
|
||||
rom.write_bytes(0xAB1E, bytearray([0xEA] * 0x01))
|
||||
|
||||
P_SWITCH_SUB_ADDR = 0x01BAA0
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x04, bytearray([0x89, 0x10])) # BIT #10
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x06, bytearray([0xF0, 0x04])) # BEQ +0x04
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x08, bytearray([0xA9, 0xB0])) # LDA #B0
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x0A, bytearray([0x80, 0x02])) # BRA +0x02
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x0C, bytearray([0xA9, 0x01])) # LDA #01
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x0E, bytearray([0x99, 0xAD, 0x14])) # STA $14AD
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(P_SWITCH_SUB_ADDR + 0x12, bytearray([0x6B])) # RTL
|
||||
# End P-Switch
|
||||
|
||||
# Spin Jump
|
||||
rom.write_bytes(0x5645, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(0x5648, bytearray([0x89, 0x08])) # BIT #08
|
||||
rom.write_bytes(0x564A, bytearray([0xF0, 0x12])) # BEQ +0x12
|
||||
rom.write_bytes(0x564C, bytearray([0x22, 0xB8, 0xBA, 0x03])) # JSL $03BAB8
|
||||
|
||||
SPIN_JUMP_SUB_ADDR = 0x01BAB8
|
||||
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x01, bytearray([0x1A])) # INC
|
||||
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x02, bytearray([0x8D, 0x0D, 0x14])) # STA $140D
|
||||
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x05, bytearray([0xA9, 0x04])) # LDA #04
|
||||
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x07, bytearray([0x8D, 0xFC, 0x1D])) # STA $1DFC
|
||||
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x0A, bytearray([0xA4, 0x76])) # LDY #76
|
||||
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x0C, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SPIN_JUMP_SUB_ADDR + 0x0D, bytearray([0x6B])) # RTL
|
||||
# End Spin Jump
|
||||
|
||||
# Spin Jump from Water
|
||||
rom.write_bytes(0x6A89, bytearray([0x22, 0xF8, 0xBB, 0x03])) # JSL $03BBF8
|
||||
rom.write_bytes(0x6A8D, bytearray([0xEA] * 0x05))
|
||||
|
||||
SPIN_JUMP_WATER_SUB_ADDR = 0x01BBF8
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x04, bytearray([0x89, 0x08])) # BIT #08
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x06, bytearray([0xF0, 0x09])) # BEQ +0x09
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x08, bytearray([0x1A])) # INC
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x09, bytearray([0x8D, 0x0D, 0x14])) # STA $140D
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x0C, bytearray([0xA9, 0x04])) # LDA #04
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x0E, bytearray([0x8D, 0xFC, 0x1D])) # STA $1DFC
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x11, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SPIN_JUMP_WATER_SUB_ADDR + 0x12, bytearray([0x6B])) # RTL
|
||||
# End Spin Jump from Water
|
||||
|
||||
# Spin Jump from Springboard
|
||||
rom.write_bytes(0xE693, bytearray([0x22, 0x0C, 0xBC, 0x03])) # JSL $03BC0C
|
||||
rom.write_bytes(0xE697, bytearray([0xEA] * 0x01))
|
||||
|
||||
SPIN_JUMP_SPRING_SUB_ADDR = 0x01BC0C
|
||||
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x04, bytearray([0x89, 0x08])) # BIT #08
|
||||
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x06, bytearray([0xF0, 0x05])) # BEQ +0x05
|
||||
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x08, bytearray([0xA9, 0x01])) # LDA #01
|
||||
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x0A, bytearray([0x8D, 0x0D, 0x14])) # STA $140D
|
||||
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x0D, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SPIN_JUMP_SPRING_SUB_ADDR + 0x0E, bytearray([0x6B])) # RTL
|
||||
# End Spin Jump from Springboard
|
||||
|
||||
# Swim
|
||||
rom.write_bytes(0x5A25, bytearray([0x22, 0xC8, 0xBA, 0x03])) # JSL $03BAC8
|
||||
rom.write_bytes(0x5A29, bytearray([0xEA] * 0x04))
|
||||
|
||||
SWIM_SUB_ADDR = 0x01BAC8
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x00, bytearray([0x48])) # PHA
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x01, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x05, bytearray([0x89, 0x04])) # BIT #04
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x07, bytearray([0xF0, 0x0C])) # BEQ +0x0C
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x09, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x0A, bytearray([0x68])) # PLA
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x0B, bytearray([0xDD, 0x84, 0xD9])) # CMP $D489, X
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x0E, bytearray([0xB0, 0x03])) # BCS +0x03
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x10, bytearray([0xBD, 0x84, 0xD9])) # LDA $D489, X
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x13, bytearray([0x80, 0x0A])) # BRA +0x0A
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x15, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x16, bytearray([0x68])) # PLA
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x17, bytearray([0xDD, 0xBE, 0xDE])) # CMP $DEBE, X
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x1A, bytearray([0xB0, 0x03])) # BCS +0x03
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x1C, bytearray([0xBD, 0xBE, 0xDE])) # LDA $DEBE, X
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x1F, bytearray([0x6B])) # RTL
|
||||
# End Swim
|
||||
|
||||
# Item Swim
|
||||
rom.write_bytes(0x59D7, bytearray([0x22, 0xE8, 0xBA, 0x03])) # JSL $03BAE8
|
||||
rom.write_bytes(0x59DB, bytearray([0xEA] * 0x02))
|
||||
|
||||
SWIM_SUB_ADDR = 0x01BAE8
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x00, bytearray([0x48])) # PHA
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x01, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x02, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x05, bytearray([0x89, 0x04])) # BIT #04
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x07, bytearray([0xF0, 0x0A])) # BEQ +0x0A
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x09, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x0A, bytearray([0x68])) # PLA
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x0B, bytearray([0xC9, 0xF0])) # CMP #F0
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x0D, bytearray([0xB0, 0x02])) # BCS +0x02
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x0F, bytearray([0xA9, 0xF0])) # LDA #F0
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x11, bytearray([0x80, 0x08])) # BRA +0x08
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x13, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x14, bytearray([0x68])) # PLA
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x15, bytearray([0xC9, 0xFF])) # CMP #FF
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x17, bytearray([0xB0, 0x02])) # BCS +0x02
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x19, bytearray([0xA9, 0x00])) # LDA #00
|
||||
rom.write_bytes(SWIM_SUB_ADDR + 0x1B, bytearray([0x6B])) # RTL
|
||||
# End Item Swim
|
||||
|
||||
# Yoshi
|
||||
rom.write_bytes(0x109FB, bytearray([0x22, 0x08, 0xBB, 0x03])) # JSL $03BB08
|
||||
rom.write_bytes(0x109FF, bytearray([0xEA] * 0x02))
|
||||
|
||||
YOSHI_SUB_ADDR = 0x01BB08
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x01, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x04, bytearray([0x89, 0x02])) # BIT #02
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x06, bytearray([0xF0, 0x06])) # BEQ +0x06
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x09, bytearray([0xB9, 0xA1, 0x88])) # LDA $88A1, Y
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x0C, bytearray([0x80, 0x04])) # BRA +0x04
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x0E, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x0F, bytearray([0xB9, 0xA2, 0x88])) # LDA $88A2, Y
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x12, bytearray([0x9D, 0x1C, 0x15])) # STA $151C, X
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x15, bytearray([0x6B])) # RTL
|
||||
# End Yoshi
|
||||
|
||||
# Baby Yoshi
|
||||
rom.write_bytes(0xA2B8, bytearray([0x22, 0x20, 0xBB, 0x03])) # JSL $03BB20
|
||||
rom.write_bytes(0xA2BC, bytearray([0xEA] * 0x01))
|
||||
|
||||
YOSHI_SUB_ADDR = 0x01BB20
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x01, bytearray([0x9C, 0x1E, 0x14])) # STZ $141E
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x04, bytearray([0xAD, 0x2C, 0x1F])) # LDA $1F2C
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x07, bytearray([0x89, 0x02])) # BIT #02
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x09, bytearray([0xF0, 0x05])) # BEQ +0x05
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x0B, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x0C, bytearray([0xA9, 0x35])) # LDA #35
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x0E, bytearray([0x80, 0x03])) # BRA +0x03
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x10, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x11, bytearray([0xA9, 0x70])) # LDA #70
|
||||
rom.write_bytes(YOSHI_SUB_ADDR + 0x13, bytearray([0x6B])) # RTL
|
||||
# End Baby Yoshi
|
||||
|
||||
# Midway Gate
|
||||
rom.write_bytes(0x72E4, bytearray([0x22, 0x38, 0xBB, 0x03])) # JSL $03BB38
|
||||
|
||||
MIDWAY_GATE_SUB_ADDR = 0x01BB38
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x04, bytearray([0x89, 0x01])) # BIT #01
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x09, bytearray([0xA9, 0x01])) # LDA #01
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x0B, bytearray([0x85, 0x19])) # STA $19
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x0D, bytearray([0x80, 0x01])) # BRA +0x01
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(MIDWAY_GATE_SUB_ADDR + 0x10, bytearray([0x6B])) # RTL
|
||||
# End Midway Gate
|
||||
|
||||
# Mushroom
|
||||
rom.write_bytes(0x5156, bytearray([0x22, 0x50, 0xBB, 0x03])) # JSL $03BB50
|
||||
rom.write_bytes(0x515A, bytearray([0xEA] * 0x04))
|
||||
|
||||
MUSHROOM_SUB_ADDR = 0x01BB50
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x04, bytearray([0x89, 0x01])) # BIT #01
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x06, bytearray([0xF0, 0x05])) # BEQ +0x05
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x09, bytearray([0xE6, 0x19])) # INC $19
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x0B, bytearray([0x80, 0x01])) # BRA +0x01
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x0D, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x0E, bytearray([0xA9, 0x00])) # LDA #00
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x10, bytearray([0x85, 0x71])) # STA $72
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x12, bytearray([0x64, 0x9D])) # STZ $9D
|
||||
rom.write_bytes(MUSHROOM_SUB_ADDR + 0x14, bytearray([0x6B])) # RTL
|
||||
# End Mushroom
|
||||
|
||||
# Take Damage
|
||||
rom.write_bytes(0x5142, bytearray([0x22, 0x65, 0xBB, 0x03])) # JSL $03BB65
|
||||
rom.write_bytes(0x5146, bytearray([0x60] * 0x01)) # RTS
|
||||
|
||||
DAMAGE_SUB_ADDR = 0x01BB65
|
||||
rom.write_bytes(DAMAGE_SUB_ADDR + 0x00, bytearray([0x8D, 0x97, 0x14])) # STA $1497
|
||||
rom.write_bytes(DAMAGE_SUB_ADDR + 0x03, bytearray([0x80, 0xF4])) # BRA -0x0C
|
||||
# End Take Damage
|
||||
|
||||
# Fire Flower Cycle
|
||||
rom.write_bytes(0x5187, bytearray([0x22, 0x6A, 0xBB, 0x03])) # JSL $03BB6A
|
||||
rom.write_bytes(0x518B, bytearray([0x60] * 0x01)) # RTS
|
||||
|
||||
PALETTE_CYCLE_SUB_ADDR = 0x01BB6A
|
||||
rom.write_bytes(PALETTE_CYCLE_SUB_ADDR + 0x00, bytearray([0xCE, 0x9B, 0x14])) # DEC $149B
|
||||
rom.write_bytes(PALETTE_CYCLE_SUB_ADDR + 0x03, bytearray([0xF0, 0xEF])) # BEQ -0x11
|
||||
rom.write_bytes(PALETTE_CYCLE_SUB_ADDR + 0x05, bytearray([0x6B])) # RTL
|
||||
# End Fire Flower Cycle
|
||||
|
||||
# Pipe Exit
|
||||
rom.write_bytes(0x526D, bytearray([0x22, 0x70, 0xBB, 0x03])) # JSL $03BB70
|
||||
rom.write_bytes(0x5271, bytearray([0x60, 0xEA] * 0x01)) # RTS, NOP
|
||||
|
||||
PIPE_EXIT_SUB_ADDR = 0x01BB70
|
||||
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x00, bytearray([0x9C, 0x19, 0x14])) # STZ $1419
|
||||
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x03, bytearray([0xA9, 0x00])) # LDA #00
|
||||
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x05, bytearray([0x85, 0x71])) # STA $72
|
||||
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x07, bytearray([0x64, 0x9D])) # STZ $9D
|
||||
rom.write_bytes(PIPE_EXIT_SUB_ADDR + 0x09, bytearray([0x6B])) # RTL
|
||||
# End Pipe Exit
|
||||
|
||||
# Cape Transform
|
||||
rom.write_bytes(0x5168, bytearray([0x22, 0x7A, 0xBB, 0x03])) # JSL $03BB7A
|
||||
rom.write_bytes(0x516C, bytearray([0xEA] * 0x01)) # RTS, NOP
|
||||
rom.write_bytes(0x516D, bytearray([0xF0, 0xD1])) # BEQ -0x2F
|
||||
|
||||
CAPE_TRANSFORM_SUB_ADDR = 0x01BB7A
|
||||
rom.write_bytes(CAPE_TRANSFORM_SUB_ADDR + 0x00, bytearray([0xA5, 0x19])) # LDA $19
|
||||
rom.write_bytes(CAPE_TRANSFORM_SUB_ADDR + 0x02, bytearray([0x4A])) # LSR
|
||||
rom.write_bytes(CAPE_TRANSFORM_SUB_ADDR + 0x03, bytearray([0xD0, 0xDF])) # BNE -0x21
|
||||
rom.write_bytes(CAPE_TRANSFORM_SUB_ADDR + 0x05, bytearray([0x6B])) # RTL
|
||||
# End Cape Transform
|
||||
|
||||
# Fire Flower
|
||||
rom.write_bytes(0xC5F7, bytearray([0x22, 0x80, 0xBB, 0x03])) # JSL $03BB80
|
||||
|
||||
FIRE_FLOWER_SUB_ADDR = 0x01BB80
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x04, bytearray([0x89, 0x02])) # BIT #02
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x09, bytearray([0xA9, 0x03])) # LDA #03
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x0B, bytearray([0x85, 0x19])) # STA $19
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x0D, bytearray([0x80, 0x01])) # BRA +0x01
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(FIRE_FLOWER_SUB_ADDR + 0x10, bytearray([0x6B])) # RTL
|
||||
# End Fire Flower
|
||||
|
||||
# Cape
|
||||
rom.write_bytes(0xC598, bytearray([0x22, 0x91, 0xBB, 0x03])) # JSL $03BB91
|
||||
|
||||
CAPE_SUB_ADDR = 0x01BB91
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x04, bytearray([0x89, 0x04])) # BIT #04
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x09, bytearray([0xA9, 0x02])) # LDA #02
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x0B, bytearray([0x85, 0x19])) # STA $19
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x0D, bytearray([0x80, 0x01])) # BRA +0x01
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(CAPE_SUB_ADDR + 0x10, bytearray([0x6B])) # RTL
|
||||
# End Cape
|
||||
|
||||
# P-Balloon
|
||||
rom.write_bytes(0xC2FF, bytearray([0x22, 0xA2, 0xBB, 0x03])) # JSL $03BBA2
|
||||
rom.write_bytes(0xC303, bytearray([0xEA] * 0x06))
|
||||
|
||||
P_BALLOON_SUB_ADDR = 0x01BBA2
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x04, bytearray([0x89, 0x08])) # BIT #08
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x06, bytearray([0xF0, 0x0D])) # BEQ +0x0D
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x09, bytearray([0xA9, 0x09])) # LDA #09
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x0B, bytearray([0x8D, 0xF3, 0x13])) # STA $13F3
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x0E, bytearray([0xA9, 0xFF])) # LDA #FF
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x10, bytearray([0x8D, 0x91, 0x18])) # STA $1891
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x13, bytearray([0x80, 0x0B])) # BRA +0x0B
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x15, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x16, bytearray([0xA9, 0x01])) # LDA #01
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x18, bytearray([0x8D, 0xF3, 0x13])) # STA $13F3
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x1B, bytearray([0xA9, 0x01])) # LDA #01
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x1D, bytearray([0x8D, 0x91, 0x18])) # STA $1891
|
||||
rom.write_bytes(P_BALLOON_SUB_ADDR + 0x20, bytearray([0x6B])) # RTL
|
||||
# End P-Balloon
|
||||
|
||||
# Star
|
||||
rom.write_bytes(0xC580, bytearray([0x22, 0xC8, 0xBB, 0x03])) # JSL $03BBC8
|
||||
rom.write_bytes(0xC584, bytearray([0xEA] * 0x01))
|
||||
|
||||
STAR_SUB_ADDR = 0x01BBC8
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x04, bytearray([0x89, 0x10])) # BIT #10
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x06, bytearray([0xF0, 0x08])) # BEQ +0x08
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x09, bytearray([0xA9, 0xFF])) # LDA #FF
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x0B, bytearray([0x8D, 0x90, 0x14])) # STA $1490
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x0E, bytearray([0x80, 0x06])) # BRA +0x06
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x10, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x11, bytearray([0xA9, 0x01])) # LDA #01
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x13, bytearray([0x8D, 0x90, 0x14])) # STA $1490
|
||||
rom.write_bytes(STAR_SUB_ADDR + 0x16, bytearray([0x6B])) # RTL
|
||||
# End Star
|
||||
|
||||
# Star Timer
|
||||
rom.write_bytes(0x62E3, bytearray([0x22, 0xE0, 0xBB, 0x03])) # JSL $03BBE0
|
||||
|
||||
STAR_TIMER_SUB_ADDR = 0x01BBE0
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x01, bytearray([0xAD, 0x2D, 0x1F])) # LDA $1F2D
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x04, bytearray([0x89, 0x10])) # BIT #10
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x06, bytearray([0xF0, 0x07])) # BEQ +0x07
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x09, bytearray([0xA5, 0x13])) # LDA $13
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x0B, bytearray([0xC0, 0x1E])) # CPY #1E
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x0D, bytearray([0x80, 0x05])) # BRA +0x05
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x0F, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x10, bytearray([0xA5, 0x13])) # LDA $13
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x12, bytearray([0xC0, 0x01])) # CPY #01
|
||||
rom.write_bytes(STAR_TIMER_SUB_ADDR + 0x14, bytearray([0x6B])) # RTL
|
||||
# End Star Timer
|
||||
|
||||
return
|
||||
|
||||
|
||||
def handle_yoshi_box(rom):
|
||||
|
||||
rom.write_bytes(0xEC3D, bytearray([0xEA] * 0x03)) # NOP Lines that cause Yoshi Rescue Box normally
|
||||
|
||||
rom.write_bytes(0x2B20F, bytearray([0x20, 0x60, 0xDC])) # JSR $05DC60
|
||||
|
||||
YOSHI_BOX_SUB_ADDR = 0x02DC60
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x01, bytearray([0xAD, 0x26, 0x14])) # LDA $1426
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x04, bytearray([0xC9, 0x03])) # CMP #03
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x06, bytearray([0xF0, 0x06])) # BEQ +0x06
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x09, bytearray([0xB9, 0xD9, 0xA5])) # LDA $A5B9, Y
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x0C, bytearray([0x80, 0x08])) # BRA +0x08
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x0E, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x0F, bytearray([0xDA])) # PHX
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x10, bytearray([0xBB])) # TYX
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x11, bytearray([0xBF, 0x00, 0xC2, 0x7E])) # LDA $7EC200, X
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x15, bytearray([0xFA])) # PLX
|
||||
rom.write_bytes(YOSHI_BOX_SUB_ADDR + 0x16, bytearray([0x60])) # RTS
|
||||
|
||||
return
|
||||
|
||||
|
||||
def handle_bowser_damage(rom):
|
||||
|
||||
rom.write_bytes(0x1A509, bytearray([0x20, 0x50, 0xBC])) # JSR $03BC50
|
||||
|
||||
BOWSER_BALLS_SUB_ADDR = 0x01BC50
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x01, bytearray([0xAD, 0x48, 0x0F])) # LDA $F48
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x04, bytearray([0xCF, 0xA1, 0xBF, 0x03])) # CMP $03BFA1
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x08, bytearray([0x90, 0x06])) # BCC +0x06
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x0A, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x0B, bytearray([0xEE, 0xB8, 0x14])) # INC $14B8
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x0E, bytearray([0x80, 0x01])) # BRA +0x01
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x10, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(BOWSER_BALLS_SUB_ADDR + 0x11, bytearray([0x60])) # RTS
|
||||
|
||||
return
|
||||
|
||||
|
||||
def handle_level_shuffle(rom, active_level_dict):
|
||||
rom.write_bytes(0x37600, bytearray([0x00] * 0x800)) # Duplicate Level Table
|
||||
|
||||
rom.write_bytes(0x2D89C, bytearray([0x00, 0xF6, 0x06])) # Level Load Pointer
|
||||
rom.write_bytes(0x20F46, bytearray([0x00, 0xF6, 0x06])) # Mid Gate Pointer
|
||||
rom.write_bytes(0x20E7B, bytearray([0x00, 0xF6, 0x06])) # Level Name Pointer
|
||||
rom.write_bytes(0x21543, bytearray([0x00, 0xF6, 0x06])) # Also Level Name Pointer?
|
||||
rom.write_bytes(0x20F64, bytearray([0x00, 0xF6, 0x06])) # Level Beaten Pointer
|
||||
|
||||
### Fix Translevel Check
|
||||
rom.write_bytes(0x2D8AE, bytearray([0x20, 0x00, 0xDD])) # JSR $DD00
|
||||
rom.write_bytes(0x2D8B1, bytearray([0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA])) # NOP NOP NOP NOP NOP
|
||||
|
||||
rom.write_bytes(0x2D7CB, bytearray([0x20, 0x00, 0xDD])) # JSR $DD00
|
||||
rom.write_bytes(0x2D7CE, bytearray([0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA])) # NOP NOP NOP NOP NOP
|
||||
|
||||
rom.write_bytes(0x2DD00, bytearray([0xDA])) # PHX
|
||||
rom.write_bytes(0x2DD01, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(0x2DD02, bytearray([0xE2, 0x30])) # SEP #30
|
||||
rom.write_bytes(0x2DD04, bytearray([0xAE, 0xBF, 0x13])) # LDX $13BF
|
||||
rom.write_bytes(0x2DD07, bytearray([0xE0, 0x25])) # CPX #25
|
||||
rom.write_bytes(0x2DD09, bytearray([0x90, 0x04])) # BCC $DD0F
|
||||
rom.write_bytes(0x2DD0B, bytearray([0xA2, 0x01])) # LDX #01
|
||||
rom.write_bytes(0x2DD0D, bytearray([0x80, 0x02])) # BRA $DD11
|
||||
rom.write_bytes(0x2DD0F, bytearray([0xA2, 0x00])) # LDX #00
|
||||
rom.write_bytes(0x2DD11, bytearray([0x86, 0x0F])) # STX $0F
|
||||
rom.write_bytes(0x2DD13, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(0x2DD14, bytearray([0xFA])) # PLX
|
||||
rom.write_bytes(0x2DD15, bytearray([0x60])) # RTS
|
||||
### End Fix Translevel Check
|
||||
|
||||
### Fix Snake Blocks
|
||||
rom.write_bytes(0x192FB, bytearray([0x20, 0x1D, 0xBC])) # JSR $03BC1D
|
||||
|
||||
SNAKE_BLOCKS_SUB_ADDR = 0x01BC1D
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x01, bytearray([0xAD, 0xBF, 0x13])) # LDA $13BF
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x04, bytearray([0xC9, 0x20])) # CMP #20
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x06, bytearray([0xF0, 0x05])) # BEQ +0x05
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x08, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x09, bytearray([0xA9, 0x01])) # LDA #01
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x0B, bytearray([0x80, 0x03])) # BRA +0x03
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x0D, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x0E, bytearray([0xA9, 0x00])) # LDA #00
|
||||
rom.write_bytes(SNAKE_BLOCKS_SUB_ADDR + 0x10, bytearray([0x60])) # RTS
|
||||
### End Fix Snake Blocks
|
||||
|
||||
for level_id, level_data in level_info_dict.items():
|
||||
if level_id not in active_level_dict.keys():
|
||||
continue
|
||||
|
||||
tile_id = active_level_dict[level_id]
|
||||
tile_data = level_info_dict[tile_id]
|
||||
|
||||
if level_id > 0x80:
|
||||
level_id = level_id - 0x50
|
||||
|
||||
rom.write_byte(tile_data.levelIDAddress, level_id)
|
||||
rom.write_byte(0x2D608 + level_id, tile_data.eventIDValue)
|
||||
|
||||
for level_id, tile_id in active_level_dict.items():
|
||||
rom.write_byte(0x37F70 + level_id, tile_id)
|
||||
|
||||
|
||||
def handle_collected_paths(rom):
|
||||
rom.write_bytes(0x1F5B, bytearray([0x22, 0x30, 0xBC, 0x03])) # JSL $03BC30
|
||||
rom.write_bytes(0x1F5F, bytearray([0xEA] * 0x02))
|
||||
|
||||
COLLECTED_PATHS_SUB_ADDR = 0x01BC30
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x00, bytearray([0x08])) # PHP
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x01, bytearray([0xAD, 0x00, 0x01])) # LDA $0100
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x04, bytearray([0xC9, 0x0B])) # CMP #0B
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x06, bytearray([0xD0, 0x04])) # BNE +0x04
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x08, bytearray([0x22, 0xAD, 0xDA, 0x04])) # JSL $04DAAD
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x0C, bytearray([0x28])) # PLP
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x0D, bytearray([0xEE, 0x00, 0x01])) # INC $0100
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x10, bytearray([0xAD, 0xAF, 0x0D])) # LDA $0DAF
|
||||
rom.write_bytes(COLLECTED_PATHS_SUB_ADDR + 0x13, bytearray([0x6B])) # RTL
|
||||
|
||||
|
||||
def handle_music_shuffle(rom, world, player):
|
||||
from .Aesthetics import generate_shuffled_level_music, generate_shuffled_ow_music, level_music_address_data, ow_music_address_data
|
||||
|
||||
shuffled_level_music = generate_shuffled_level_music(world, player)
|
||||
for i in range(len(shuffled_level_music)):
|
||||
rom.write_byte(level_music_address_data[i], shuffled_level_music[i])
|
||||
|
||||
shuffled_ow_music = generate_shuffled_ow_music(world, player)
|
||||
for i in range(len(shuffled_ow_music)):
|
||||
for addr in ow_music_address_data[i]:
|
||||
rom.write_byte(addr, shuffled_ow_music[i])
|
||||
|
||||
|
||||
def handle_mario_palette(rom, world, player):
|
||||
from .Aesthetics import mario_palettes, fire_mario_palettes, ow_mario_palettes
|
||||
|
||||
chosen_palette = world.mario_palette[player].value
|
||||
|
||||
rom.write_bytes(0x32C8, bytes(mario_palettes[chosen_palette]))
|
||||
rom.write_bytes(0x32F0, bytes(fire_mario_palettes[chosen_palette]))
|
||||
rom.write_bytes(0x359C, bytes(ow_mario_palettes[chosen_palette]))
|
||||
|
||||
|
||||
def handle_swap_donut_gh_exits(rom):
|
||||
rom.write_bytes(0x2567C, bytes([0xC0]))
|
||||
rom.write_bytes(0x25873, bytes([0xA9]))
|
||||
rom.write_bytes(0x25875, bytes([0x85]))
|
||||
rom.write_bytes(0x25954, bytes([0x92]))
|
||||
rom.write_bytes(0x25956, bytes([0x0A]))
|
||||
rom.write_bytes(0x25E31, bytes([0x00, 0x00, 0xD8, 0x04, 0x24, 0x00, 0x98, 0x04, 0x48, 0x00, 0xD8, 0x03, 0x6C, 0x00, 0x56, 0x03,
|
||||
0x90, 0x00, 0x56, 0x03, 0xB4, 0x00, 0x56, 0x03, 0x10, 0x05, 0x18, 0x05, 0x28, 0x09, 0x24, 0x05,
|
||||
0x38, 0x0B, 0x14, 0x07, 0xEC, 0x09, 0x12, 0x05, 0xF0, 0x09, 0xD2, 0x04, 0xF4, 0x09, 0x92, 0x04]))
|
||||
rom.write_bytes(0x26371, bytes([0x32]))
|
||||
|
||||
|
||||
def patch_rom(world, rom, player, active_level_dict):
|
||||
local_random = world.slot_seeds[player]
|
||||
|
||||
goal_text = generate_goal_text(world, player)
|
||||
|
||||
rom.write_bytes(0x2A6E2, goal_text)
|
||||
rom.write_byte(0x2B1D8, 0x80)
|
||||
|
||||
intro_text = generate_text_box("Bowser has stolen all of Mario's abilities. Can you help Mario travel across Dinosaur land to get them back and save the Princess from him?")
|
||||
rom.write_bytes(0x2A5D9, intro_text)
|
||||
|
||||
# Force all 8 Bowser's Castle Rooms
|
||||
rom.write_byte(0x3A680, 0xD4)
|
||||
rom.write_byte(0x3A684, 0xD4)
|
||||
rom.write_byte(0x3A688, 0xD4)
|
||||
rom.write_byte(0x3A68C, 0xD4)
|
||||
rom.write_byte(0x3A705, 0xD3)
|
||||
rom.write_byte(0x3A763, 0xD2)
|
||||
rom.write_byte(0x3A800, 0xD1)
|
||||
rom.write_byte(0x3A83D, 0xCF)
|
||||
rom.write_byte(0x3A932, 0xCE)
|
||||
rom.write_byte(0x3A9E1, 0xCD)
|
||||
rom.write_byte(0x3AA75, 0xCC)
|
||||
|
||||
# Prevent Title Screen Deaths
|
||||
rom.write_byte(0x1C6A, 0x80)
|
||||
|
||||
# Title Screen Text
|
||||
player_name_bytes = bytearray()
|
||||
player_name = world.get_player_name(player)
|
||||
for i in range(16):
|
||||
char = " "
|
||||
if i < len(player_name):
|
||||
char = world.get_player_name(player)[i]
|
||||
upper_char = char.upper()
|
||||
if upper_char not in title_text_mapping:
|
||||
for byte in title_text_mapping["."]:
|
||||
player_name_bytes.append(byte)
|
||||
else:
|
||||
for byte in title_text_mapping[upper_char]:
|
||||
player_name_bytes.append(byte)
|
||||
|
||||
rom.write_bytes(0x2B7F1, player_name_bytes) # MARIO A
|
||||
rom.write_bytes(0x2B726, player_name_bytes) # MARIO A
|
||||
|
||||
rom.write_bytes(0x2B815, bytearray([0xFC, 0x38] * 0x10)) # MARIO B
|
||||
rom.write_bytes(0x2B74A, bytearray([0xFC, 0x38] * 0x10)) # MARIO B
|
||||
rom.write_bytes(0x2B839, bytearray([0x71, 0x31, 0x74, 0x31, 0x2D, 0x31, 0x84, 0x30,
|
||||
0x82, 0x30, 0x6F, 0x31, 0x73, 0x31, 0x70, 0x31,
|
||||
0x71, 0x31, 0x75, 0x31, 0x83, 0x30, 0xFC, 0x38,
|
||||
0xFC, 0x38, 0xFC, 0x38, 0xFC, 0x38, 0xFC, 0x38])) # MARIO C
|
||||
rom.write_bytes(0x2B76E, bytearray([0xFC, 0x38] * 0x10)) # MARIO C
|
||||
rom.write_bytes(0x2B79E, bytearray([0xFC, 0x38] * 0x05)) # EMPTY
|
||||
rom.write_bytes(0x2B7AE, bytearray([0xFC, 0x38] * 0x05)) # EMPTY
|
||||
rom.write_bytes(0x2B8A8, bytearray([0xFC, 0x38] * 0x0D)) # 2 PLAYER GAME
|
||||
|
||||
rom.write_bytes(0x2B85D, bytearray([0xFC, 0x38] * 0x0A)) # ERASE
|
||||
|
||||
rom.write_bytes(0x2B88E, bytearray([0x2C, 0x31, 0x73, 0x31, 0x75, 0x31, 0x82, 0x30, 0x30, 0x31, 0xFC, 0x38, 0x31, 0x31, 0x73, 0x31,
|
||||
0x73, 0x31, 0x7C, 0x30, 0xFC, 0x38, 0xFC, 0x38, 0xFC, 0x38])) # 1 Player Game
|
||||
|
||||
rom.write_bytes(0x2B6D7, bytearray([0xFC, 0x38, 0xFC, 0x38, 0x16, 0x38, 0x18, 0x38, 0x0D, 0x38, 0xFC, 0x38, 0x0B, 0x38, 0x22, 0x38,
|
||||
0xFC, 0x38, 0x19, 0x38, 0x18, 0x38, 0x1B, 0x38, 0x22, 0x38, 0x10, 0x38, 0x18, 0x38, 0x17, 0x38,
|
||||
0x0E, 0x38, 0xFC, 0x38, 0xFC, 0x38])) # Mod by PoryGone
|
||||
|
||||
# Title Options
|
||||
rom.write_bytes(0x1E6A, bytearray([0x01]))
|
||||
rom.write_bytes(0x1E6C, bytearray([0x01]))
|
||||
rom.write_bytes(0x1E6E, bytearray([0x01]))
|
||||
|
||||
# Always allow Start+Select
|
||||
rom.write_bytes(0x2267, bytearray([0xEA, 0xEA]))
|
||||
|
||||
# Always bring up save prompt on beating a level
|
||||
if world.autosave[player]:
|
||||
rom.write_bytes(0x20F93, bytearray([0x00]))
|
||||
|
||||
# Starting Life Count
|
||||
rom.write_bytes(0x1E25, bytearray([world.starting_life_count[player].value - 1]))
|
||||
|
||||
# Repurpose Bonus Stars counter for Boss Token or Yoshi Eggs
|
||||
rom.write_bytes(0x3F1AA, bytearray([0x00] * 0x20))
|
||||
rom.write_bytes(0x20F9F, bytearray([0xEA] * 0x3B))
|
||||
|
||||
# Prevent Switch Palaces setting the Switch Palace flags
|
||||
rom.write_bytes(0x6EC9A, bytearray([0xEA, 0xEA]))
|
||||
rom.write_bytes(0x6EB1, bytearray([0xEA, 0xEA]))
|
||||
rom.write_bytes(0x6EB4, bytearray([0xEA, 0xEA, 0xEA]))
|
||||
|
||||
handle_ability_code(rom)
|
||||
|
||||
handle_yoshi_box(rom)
|
||||
handle_bowser_damage(rom)
|
||||
|
||||
handle_collected_paths(rom)
|
||||
|
||||
# Handle Level Shuffle
|
||||
handle_level_shuffle(rom, active_level_dict)
|
||||
|
||||
# Handle Music Shuffle
|
||||
if world.music_shuffle[player] != "none":
|
||||
handle_music_shuffle(rom, world, player)
|
||||
|
||||
generate_shuffled_header_data(rom, world, player)
|
||||
|
||||
if world.swap_donut_gh_exits[player]:
|
||||
handle_swap_donut_gh_exits(rom)
|
||||
|
||||
handle_mario_palette(rom, world, player)
|
||||
|
||||
# Store all relevant option results in ROM
|
||||
rom.write_byte(0x01BFA0, world.goal[player].value)
|
||||
rom.write_byte(0x01BFA1, world.bosses_required[player].value)
|
||||
required_yoshi_eggs = max(math.floor(
|
||||
world.number_of_yoshi_eggs[player].value * (world.percentage_of_yoshi_eggs[player].value / 100.0)), 1)
|
||||
rom.write_byte(0x01BFA2, required_yoshi_eggs)
|
||||
#rom.write_byte(0x01BFA3, world.display_sent_item_popups[player].value)
|
||||
rom.write_byte(0x01BFA4, world.display_received_item_popups[player].value)
|
||||
rom.write_byte(0x01BFA5, world.death_link[player].value)
|
||||
rom.write_byte(0x01BFA6, world.dragon_coin_checks[player].value)
|
||||
rom.write_byte(0x01BFA7, world.swap_donut_gh_exits[player].value)
|
||||
|
||||
|
||||
from Main import __version__
|
||||
rom.name = bytearray(f'SMW{__version__.replace(".", "")[0:3]}_{player}_{world.seed:11}\0', 'utf8')[:21]
|
||||
rom.name.extend([0] * (21 - len(rom.name)))
|
||||
rom.write_bytes(0x7FC0, rom.name)
|
||||
|
||||
|
||||
def get_base_rom_bytes(file_name: str = "") -> bytes:
|
||||
base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None)
|
||||
if not base_rom_bytes:
|
||||
file_name = get_base_rom_path(file_name)
|
||||
base_rom_bytes = bytes(Utils.read_snes_rom(open(file_name, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(base_rom_bytes)
|
||||
if USHASH != basemd5.hexdigest():
|
||||
raise Exception('Supplied Base Rom does not match known MD5 for US(1.0) release. '
|
||||
'Get the correct game and version, then dump it')
|
||||
get_base_rom_bytes.base_rom_bytes = base_rom_bytes
|
||||
return base_rom_bytes
|
||||
|
||||
|
||||
def get_base_rom_path(file_name: str = "") -> str:
|
||||
options = Utils.get_options()
|
||||
if not file_name:
|
||||
file_name = options["smw_options"]["rom_file"]
|
||||
if not os.path.exists(file_name):
|
||||
file_name = Utils.local_path(file_name)
|
||||
return file_name
|
||||
20
worlds/smw/Rules.py
Normal file
20
worlds/smw/Rules.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import math
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
from .Names import LocationName, ItemName
|
||||
from ..AutoWorld import LogicMixin
|
||||
from ..generic.Rules import add_rule, set_rule
|
||||
|
||||
|
||||
def set_rules(world: MultiWorld, player: int):
|
||||
|
||||
if world.goal[player] == "yoshi_egg_hunt":
|
||||
required_yoshi_eggs = max(math.floor(
|
||||
world.number_of_yoshi_eggs[player].value * (world.percentage_of_yoshi_eggs[player].value / 100.0)), 1)
|
||||
|
||||
add_rule(world.get_location(LocationName.yoshis_house, player),
|
||||
lambda state: state.has(ItemName.yoshi_egg, player, required_yoshi_eggs))
|
||||
else:
|
||||
add_rule(world.get_location(LocationName.bowser, player), lambda state: state.has(ItemName.mario_carry, player))
|
||||
|
||||
world.completion_condition[player] = lambda state: state.has(ItemName.victory, player)
|
||||
249
worlds/smw/__init__.py
Normal file
249
worlds/smw/__init__.py
Normal file
@@ -0,0 +1,249 @@
|
||||
import os
|
||||
import typing
|
||||
import math
|
||||
import threading
|
||||
|
||||
from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification
|
||||
from .Items import SMWItem, ItemData, item_table
|
||||
from .Locations import SMWLocation, all_locations, setup_locations
|
||||
from .Options import smw_options
|
||||
from .Regions import create_regions, connect_regions
|
||||
from .Levels import full_level_list, generate_level_list, location_id_to_level_id
|
||||
from .Rules import set_rules
|
||||
from ..generic.Rules import add_rule
|
||||
from .Names import ItemName, LocationName
|
||||
from ..AutoWorld import WebWorld, World
|
||||
from .Rom import LocalRom, patch_rom, get_base_rom_path, SMWDeltaPatch
|
||||
|
||||
|
||||
class SMWWeb(WebWorld):
|
||||
theme = "grass"
|
||||
|
||||
setup_en = Tutorial(
|
||||
"Multiworld Setup Guide",
|
||||
"A guide to setting up the Super Mario World randomizer connected to an Archipelago Multiworld.",
|
||||
"English",
|
||||
"setup_en.md",
|
||||
"setup/en",
|
||||
["PoryGone"]
|
||||
)
|
||||
|
||||
tutorials = [setup_en]
|
||||
|
||||
|
||||
class SMWWorld(World):
|
||||
"""
|
||||
Super Mario World is an action platforming game.
|
||||
The Princess has been kidnapped by Bowser again, but Mario has somehow
|
||||
lost all of his abilities. Can he get them back in time to save the Princess?
|
||||
"""
|
||||
game: str = "Super Mario World"
|
||||
option_definitions = smw_options
|
||||
topology_present = False
|
||||
data_version = 1
|
||||
required_client_version = (0, 3, 5)
|
||||
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = all_locations
|
||||
|
||||
active_level_dict: typing.Dict[int,int]
|
||||
web = SMWWeb()
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
self.rom_name_available_event = threading.Event()
|
||||
super().__init__(world, player)
|
||||
|
||||
@classmethod
|
||||
def stage_assert_generate(cls, world):
|
||||
rom_file = get_base_rom_path()
|
||||
if not os.path.exists(rom_file):
|
||||
raise FileNotFoundError(rom_file)
|
||||
|
||||
def _get_slot_data(self):
|
||||
return {
|
||||
#"death_link": self.world.death_link[self.player].value,
|
||||
"active_levels": self.active_level_dict,
|
||||
}
|
||||
|
||||
def _create_items(self, name: str):
|
||||
data = item_table[name]
|
||||
return [self.create_item(name)] * data.quantity
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
slot_data = self._get_slot_data()
|
||||
for option_name in smw_options:
|
||||
option = getattr(self.world, option_name)[self.player]
|
||||
slot_data[option_name] = option.value
|
||||
|
||||
return slot_data
|
||||
|
||||
def generate_basic(self):
|
||||
itempool: typing.List[SMWItem] = []
|
||||
|
||||
self.active_level_dict = dict(zip(generate_level_list(self.world, self.player), full_level_list))
|
||||
self.topology_present = self.world.level_shuffle[self.player]
|
||||
|
||||
connect_regions(self.world, self.player, self.active_level_dict)
|
||||
|
||||
# Add Boss Token amount requirements for Worlds
|
||||
add_rule(self.world.get_region(LocationName.donut_plains_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 1))
|
||||
add_rule(self.world.get_region(LocationName.vanilla_dome_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 2))
|
||||
add_rule(self.world.get_region(LocationName.forest_of_illusion_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 4))
|
||||
add_rule(self.world.get_region(LocationName.chocolate_island_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 5))
|
||||
add_rule(self.world.get_region(LocationName.valley_of_bowser_1_tile, self.player).entrances[0], lambda state: state.has(ItemName.koopaling, self.player, 6))
|
||||
|
||||
total_required_locations = 96
|
||||
if self.world.dragon_coin_checks[self.player]:
|
||||
total_required_locations += 49
|
||||
|
||||
itempool += [self.create_item(ItemName.mario_run)]
|
||||
itempool += [self.create_item(ItemName.mario_carry)]
|
||||
itempool += [self.create_item(ItemName.mario_swim)]
|
||||
itempool += [self.create_item(ItemName.mario_spin_jump)]
|
||||
itempool += [self.create_item(ItemName.mario_climb)]
|
||||
itempool += [self.create_item(ItemName.yoshi_activate)]
|
||||
itempool += [self.create_item(ItemName.p_switch)]
|
||||
itempool += [self.create_item(ItemName.p_balloon)]
|
||||
itempool += [self.create_item(ItemName.super_star_active)]
|
||||
itempool += [self.create_item(ItemName.progressive_powerup)] * 3
|
||||
itempool += [self.create_item(ItemName.yellow_switch_palace)]
|
||||
itempool += [self.create_item(ItemName.green_switch_palace)]
|
||||
itempool += [self.create_item(ItemName.red_switch_palace)]
|
||||
itempool += [self.create_item(ItemName.blue_switch_palace)]
|
||||
|
||||
if self.world.goal[self.player] == "yoshi_egg_hunt":
|
||||
itempool += [self.create_item(ItemName.yoshi_egg)] * self.world.number_of_yoshi_eggs[self.player]
|
||||
self.world.get_location(LocationName.yoshis_house, self.player).place_locked_item(self.create_item(ItemName.victory))
|
||||
else:
|
||||
self.world.get_location(LocationName.bowser, self.player).place_locked_item(self.create_item(ItemName.victory))
|
||||
|
||||
junk_count = total_required_locations - len(itempool)
|
||||
trap_weights = []
|
||||
trap_weights += ([ItemName.ice_trap] * self.world.ice_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.stun_trap] * self.world.stun_trap_weight[self.player].value)
|
||||
trap_weights += ([ItemName.literature_trap] * self.world.literature_trap_weight[self.player].value)
|
||||
trap_count = 0 if (len(trap_weights) == 0) else math.ceil(junk_count * (self.world.trap_fill_percentage[self.player].value / 100.0))
|
||||
junk_count -= trap_count
|
||||
|
||||
trap_pool = []
|
||||
for i in range(trap_count):
|
||||
trap_item = self.world.random.choice(trap_weights)
|
||||
trap_pool += [self.create_item(trap_item)]
|
||||
|
||||
itempool += trap_pool
|
||||
|
||||
itempool += [self.create_item(ItemName.one_up_mushroom)] * junk_count
|
||||
|
||||
boss_location_names = [LocationName.yoshis_island_koopaling, LocationName.donut_plains_koopaling, LocationName.vanilla_dome_koopaling,
|
||||
LocationName.twin_bridges_koopaling, LocationName.forest_koopaling, LocationName.chocolate_koopaling,
|
||||
LocationName.valley_koopaling, LocationName.vanilla_reznor, LocationName.forest_reznor, LocationName.chocolate_reznor, LocationName.valley_reznor]
|
||||
|
||||
for location_name in boss_location_names:
|
||||
self.world.get_location(location_name, self.player).place_locked_item(self.create_item(ItemName.koopaling))
|
||||
|
||||
self.world.itempool += itempool
|
||||
|
||||
|
||||
def generate_output(self, output_directory: str):
|
||||
rompath = "" # if variable is not declared finally clause may fail
|
||||
try:
|
||||
world = self.world
|
||||
player = self.player
|
||||
|
||||
rom = LocalRom(get_base_rom_path())
|
||||
patch_rom(self.world, rom, self.player, self.active_level_dict)
|
||||
|
||||
rompath = os.path.join(output_directory, f"{self.world.get_out_file_name_base(self.player)}.sfc")
|
||||
rom.write_to_file(rompath)
|
||||
self.rom_name = rom.name
|
||||
|
||||
patch = SMWDeltaPatch(os.path.splitext(rompath)[0]+SMWDeltaPatch.patch_file_ending, player=player,
|
||||
player_name=world.player_name[player], patched_path=rompath)
|
||||
patch.write()
|
||||
except:
|
||||
raise
|
||||
finally:
|
||||
self.rom_name_available_event.set() # make sure threading continues and errors are collected
|
||||
if os.path.exists(rompath):
|
||||
os.unlink(rompath)
|
||||
|
||||
def modify_multidata(self, multidata: dict):
|
||||
import base64
|
||||
# wait for self.rom_name to be available.
|
||||
self.rom_name_available_event.wait()
|
||||
rom_name = getattr(self, "rom_name", None)
|
||||
# we skip in case of error, so that the original error in the output thread is the one that gets raised
|
||||
if rom_name:
|
||||
new_name = base64.b64encode(bytes(self.rom_name)).decode()
|
||||
multidata["connect_names"][new_name] = multidata["connect_names"][self.world.player_name[self.player]]
|
||||
|
||||
def extend_hint_information(self, hint_data: typing.Dict[int, typing.Dict[int, str]]):
|
||||
if self.topology_present:
|
||||
world_names = [
|
||||
LocationName.yoshis_island_region,
|
||||
LocationName.donut_plains_region,
|
||||
LocationName.vanilla_dome_region,
|
||||
LocationName.twin_bridges_region,
|
||||
LocationName.forest_of_illusion_region,
|
||||
LocationName.chocolate_island_region,
|
||||
LocationName.valley_of_bowser_region,
|
||||
LocationName.star_road_region,
|
||||
LocationName.special_zone_region,
|
||||
]
|
||||
world_cutoffs = [
|
||||
0x07,
|
||||
0x13,
|
||||
0x1F,
|
||||
0x26,
|
||||
0x30,
|
||||
0x39,
|
||||
0x44,
|
||||
0x4F,
|
||||
0x59
|
||||
]
|
||||
er_hint_data = {}
|
||||
for loc_name, level_data in location_id_to_level_id.items():
|
||||
level_id = level_data[0]
|
||||
|
||||
if level_id not in self.active_level_dict:
|
||||
continue
|
||||
|
||||
keys_list = list(self.active_level_dict.keys())
|
||||
level_index = keys_list.index(level_id)
|
||||
for i in range(len(world_cutoffs)):
|
||||
if level_index >= world_cutoffs[i]:
|
||||
continue
|
||||
|
||||
if self.world.dragon_coin_checks[self.player].value == 0 and "Dragon Coins" in loc_name:
|
||||
continue
|
||||
|
||||
location = self.world.get_location(loc_name, self.player)
|
||||
er_hint_data[location.address] = world_names[i]
|
||||
break
|
||||
|
||||
hint_data[self.player] = er_hint_data
|
||||
|
||||
def create_regions(self):
|
||||
location_table = setup_locations(self.world, self.player)
|
||||
create_regions(self.world, self.player, location_table)
|
||||
|
||||
def create_item(self, name: str, force_non_progression=False) -> Item:
|
||||
data = item_table[name]
|
||||
|
||||
if force_non_progression:
|
||||
classification = ItemClassification.filler
|
||||
elif name == ItemName.yoshi_egg:
|
||||
classification = ItemClassification.progression_skip_balancing
|
||||
elif data.progression:
|
||||
classification = ItemClassification.progression
|
||||
elif data.trap:
|
||||
classification = ItemClassification.trap
|
||||
else:
|
||||
classification = ItemClassification.filler
|
||||
|
||||
created_item = SMWItem(name, classification, data.code, self.player)
|
||||
|
||||
return created_item
|
||||
|
||||
def set_rules(self):
|
||||
set_rules(self.world, self.player)
|
||||
43
worlds/smw/docs/en_Super Mario World.md
Normal file
43
worlds/smw/docs/en_Super Mario World.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Super Mario World
|
||||
|
||||
## Where is the settings page?
|
||||
|
||||
The [player settings page for this game](../player-settings) contains all the options you need to configure and export a config file.
|
||||
|
||||
## What does randomization do to this game?
|
||||
|
||||
Mario's basic abilities are removed, and placed into the item pool as items that any player can find. This includes:
|
||||
- Carry
|
||||
- Climb
|
||||
- Run
|
||||
- P-Switch
|
||||
- Swim
|
||||
- Spin Jump
|
||||
- Yoshi
|
||||
|
||||
Additionally, the ability to use powerups (Mushrooms, Fire Flowers, Capes, Stars, and P-Balloons) are shuffled into the item pool, as are the Four Switch Palaces.
|
||||
|
||||
## What is the goal of Super Mario World when randomized?
|
||||
|
||||
There are two goals which can be chosen:
|
||||
- `Bowser`: Reach Bowser's Castle and defeat Bowser, after defeating a certain number of bosses.
|
||||
- `Yoshi Egg Hunt`: Collect a certain number of Yoshi Eggs, then return to Yoshi's House
|
||||
|
||||
## What items and locations get shuffled?
|
||||
|
||||
Each unique level exit awards a location check. Optionally, collecting five Dragon Coins in each level can also award a location check.
|
||||
Mario's various abilities and powerups as described above are placed into the item pool.
|
||||
If the player is playing Yoshi Egg Hunt, a certain number of Yoshi Eggs will be placed into the item pool.
|
||||
Any additional items that are needed to fill out the item pool with be 1-Up Mushrooms.
|
||||
|
||||
## Which items can be in another player's world?
|
||||
|
||||
Any shuffled item can be in other players' worlds.
|
||||
|
||||
## What does another world's item look like in Super Mario World
|
||||
|
||||
Items do not have an appearance in Super Mario World.
|
||||
|
||||
## When the player receives an item, what happens?
|
||||
|
||||
The player can choose to receive a text box in-game when they receive an item. Regardless of that choice, items will be queued, and granted when the player next enters a level.
|
||||
149
worlds/smw/docs/setup_en.md
Normal file
149
worlds/smw/docs/setup_en.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Super Mario World Randomizer Setup Guide
|
||||
|
||||
## Required Software
|
||||
|
||||
- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases). Make sure to check the box for `SNI Client - Super Mario World Patch Setup`
|
||||
|
||||
|
||||
- Hardware or software capable of loading and playing SNES ROM files
|
||||
- An emulator capable of connecting to SNI such as:
|
||||
- snes9x-rr from: [snes9x rr](https://github.com/gocha/snes9x-rr/releases),
|
||||
- BizHawk from: [BizHawk Website](http://tasvideos.org/BizHawk.html)
|
||||
- RetroArch 1.10.3 or newer from: [RetroArch Website](https://retroarch.com?page=platforms). Or,
|
||||
- An SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other
|
||||
compatible hardware
|
||||
- Your legally obtained Super Mario World ROM file, probably named `Super Mario World (USA).sfc`
|
||||
|
||||
## Installation Procedures
|
||||
|
||||
### Windows Setup
|
||||
|
||||
1. During the installation of Archipelago, you will have been asked to install the SNI Client. If you did not do this,
|
||||
or you are on an older version, you may run the installer again to install the SNI Client.
|
||||
2. During setup, you will be asked to locate your base ROM file. This is your Super Mario World ROM file.
|
||||
3. If you are using an emulator, you should assign your Lua capable emulator as your default program for launching ROM
|
||||
files.
|
||||
1. Extract your emulator's folder to your Desktop, or somewhere you will remember.
|
||||
2. Right-click on a ROM file and select **Open with...**
|
||||
3. Check the box next to **Always use this app to open .sfc files**
|
||||
4. Scroll to the bottom of the list and click the grey text **Look for another App on this PC**
|
||||
5. Browse for your emulator's `.exe` file and click **Open**. This file should be located inside the folder you
|
||||
extracted in step one.
|
||||
|
||||
## Create a Config (.yaml) File
|
||||
|
||||
### What is a config file and why do I need one?
|
||||
|
||||
See the guide on setting up a basic YAML at the Archipelago setup
|
||||
guide: [Basic Multiworld Setup Guide](/tutorial/Archipelago/setup/en)
|
||||
|
||||
### Where do I get a config file?
|
||||
|
||||
The Player Settings page on the website allows you to configure your personal settings and export a config file from
|
||||
them. Player settings page: [Super Mario World Player Settings Page](/games/Super%20Mario%20World/player-settings)
|
||||
|
||||
### Verifying your config file
|
||||
|
||||
If you would like to validate your config file to make sure it works, you may do so on the YAML Validator page. YAML
|
||||
validator page: [YAML Validation page](/mysterycheck)
|
||||
|
||||
## Joining a MultiWorld Game
|
||||
|
||||
### Obtain your patch file and create your ROM
|
||||
|
||||
When you join a multiworld game, you will be asked to provide your config file to whomever is hosting. Once that is done,
|
||||
the host will provide you with either a link to download your patch file, or with a zip file containing everyone's patch
|
||||
files. Your patch file should have a `.apsmw` extension.
|
||||
|
||||
Put your patch file on your desktop or somewhere convenient, and double click it. This should automatically launch the
|
||||
client, and will also create your ROM in the same place as your patch file.
|
||||
|
||||
### Connect to the client
|
||||
|
||||
#### With an emulator
|
||||
|
||||
When the client launched automatically, SNI should have also automatically launched in the background. If this is its
|
||||
first time launching, you may be prompted to allow it to communicate through the Windows Firewall.
|
||||
|
||||
##### snes9x-rr
|
||||
|
||||
1. Load your ROM file if it hasn't already been loaded.
|
||||
2. Click on the File menu and hover on **Lua Scripting**
|
||||
3. Click on **New Lua Script Window...**
|
||||
4. In the new window, click **Browse...**
|
||||
5. Select the connector lua file included with your client
|
||||
- Look in the Archipelago folder for `/SNI/lua/x64` or `/SNI/lua/x86` depending on if the
|
||||
emulator is 64-bit or 32-bit.
|
||||
6. If you see an error while loading the script that states `socket.dll missing` or similar, navigate to the folder of
|
||||
the lua you are using in your file explorer and copy the `socket.dll` to the base folder of your snes9x install.
|
||||
|
||||
##### BizHawk
|
||||
|
||||
1. Ensure you have the BSNES core loaded. You may do this by clicking on the Tools menu in BizHawk and following these
|
||||
menu options:
|
||||
`Config --> Cores --> SNES --> BSNES`
|
||||
Once you have changed the loaded core, you must restart BizHawk.
|
||||
2. Load your ROM file if it hasn't already been loaded.
|
||||
3. Click on the Tools menu and click on **Lua Console**
|
||||
4. Click the button to open a new Lua script.
|
||||
5. Select the `Connector.lua` file included with your client
|
||||
- Look in the Archipelago folder for `/SNI/lua/x64` or `/SNI/lua/x86` depending on if the
|
||||
emulator is 64-bit or 32-bit. Please note the most recent versions of BizHawk are 64-bit only.
|
||||
|
||||
##### RetroArch 1.10.3 or newer
|
||||
|
||||
You only have to do these steps once. Note, RetroArch 1.9.x will not work as it is older than 1.10.3.
|
||||
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
When loading a ROM, be sure to select a **bsnes-mercury** core. These are the only cores that allow external tools to
|
||||
read ROM data.
|
||||
|
||||
#### With hardware
|
||||
|
||||
This guide assumes you have downloaded the correct firmware for your device. If you have not done so already, please do
|
||||
this now. SD2SNES and FXPak Pro users may download the appropriate firmware on the SD2SNES releases page. SD2SNES
|
||||
releases page: [SD2SNES Releases Page](https://github.com/RedGuyyyy/sd2snes/releases)
|
||||
|
||||
Other hardware may find helpful information on the usb2snes platforms
|
||||
page: [usb2snes Supported Platforms Page](http://usb2snes.com/#supported-platforms)
|
||||
|
||||
1. Close your emulator, which may have auto-launched.
|
||||
2. Power on your device and load the ROM.
|
||||
|
||||
### Connect to the Archipelago Server
|
||||
|
||||
The patch file which launched your client should have automatically connected you to the AP Server. There are a few
|
||||
reasons this may not happen however, including if the game is hosted on the website but was generated elsewhere. If the
|
||||
client window shows "Server Status: Not Connected", simply ask the host for the address of the server, and copy/paste it
|
||||
into the "Server" input field then press enter.
|
||||
|
||||
The client will attempt to reconnect to the new server address, and should momentarily show "Server Status: Connected".
|
||||
|
||||
### Play the game
|
||||
|
||||
When the client shows both SNES Device and Server as connected, you're ready to begin playing. Congratulations on
|
||||
successfully joining a multiworld game!
|
||||
|
||||
## Hosting a MultiWorld game
|
||||
|
||||
The recommended way to host a game is to use our hosting service. The process is relatively simple:
|
||||
|
||||
1. Collect config files from your players.
|
||||
2. Create a zip file containing your players' config files.
|
||||
3. Upload that zip file to the Generate page above.
|
||||
- Generate page: [WebHost Seed Generation Page](/generate)
|
||||
4. Wait a moment while the seed is generated.
|
||||
5. When the seed is generated, you will be redirected to a "Seed Info" page.
|
||||
6. Click "Create New Room". This will take you to the server page. Provide the link to this page to your players, so
|
||||
they may download their patch files from there.
|
||||
7. Note that a link to a MultiWorld Tracker is at the top of the room page. The tracker shows the progress of all
|
||||
players in the game. Any observers may also be given the link to this page.
|
||||
8. Once all players have joined, you may begin playing.
|
||||
@@ -2,7 +2,8 @@ import hashlib
|
||||
import os
|
||||
|
||||
import Utils
|
||||
from Patch import read_rom, APDeltaPatch
|
||||
from Utils import read_snes_rom
|
||||
from worlds.Files import APDeltaPatch
|
||||
|
||||
SMJUHASH = '21f3e98df4780ee1c667b84e57d88675'
|
||||
LTTPJPN10HASH = '03a63945398191337e896e5771f77173'
|
||||
@@ -23,7 +24,7 @@ def get_base_rom_bytes() -> bytes:
|
||||
base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None)
|
||||
if not base_rom_bytes:
|
||||
sm_file_name = get_sm_base_rom_path()
|
||||
sm_base_rom_bytes = bytes(read_rom(open(sm_file_name, "rb")))
|
||||
sm_base_rom_bytes = bytes(read_snes_rom(open(sm_file_name, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(sm_base_rom_bytes)
|
||||
@@ -31,7 +32,7 @@ def get_base_rom_bytes() -> bytes:
|
||||
raise Exception('Supplied Base Rom does not match known MD5 for SM Japan+US release. '
|
||||
'Get the correct game and version, then dump it')
|
||||
lttp_file_name = get_lttp_base_rom_path()
|
||||
lttp_base_rom_bytes = bytes(read_rom(open(lttp_file_name, "rb")))
|
||||
lttp_base_rom_bytes = bytes(read_snes_rom(open(lttp_file_name, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(lttp_base_rom_bytes)
|
||||
|
||||
@@ -426,11 +426,9 @@ class SMZ3World(World):
|
||||
base_combined_rom[addr + offset] = byte
|
||||
offset += 1
|
||||
|
||||
outfilebase = 'AP_' + self.world.seed_name
|
||||
outfilepname = f'_P{self.player}'
|
||||
outfilepname += f"_{self.world.get_file_safe_player_name(self.player).replace(' ', '_')}" \
|
||||
outfilebase = self.world.get_out_file_name_base(self.player)
|
||||
|
||||
filename = os.path.join(output_directory, f'{outfilebase}{outfilepname}.sfc')
|
||||
filename = os.path.join(output_directory, f"{outfilebase}.sfc")
|
||||
with open(filename, "wb") as binary_file:
|
||||
binary_file.write(base_combined_rom)
|
||||
patch = SMZ3DeltaPatch(os.path.splitext(filename)[0]+SMZ3DeltaPatch.patch_file_ending, player=self.player,
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
`SNI Client - A Link to the Past Patch Setup`
|
||||
- Hardware or software capable of loading and playing SNES ROM files
|
||||
- An emulator capable of connecting to SNI such as:
|
||||
- snes9x Multitroid
|
||||
from: [snes9x Multitroid Download](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz),
|
||||
- snes9x-rr from: [snes9x rr](https://github.com/gocha/snes9x-rr/releases),
|
||||
- BizHawk from: [BizHawk Website](http://tasvideos.org/BizHawk.html), or
|
||||
- RetroArch 1.10.3 or newer from: [RetroArch Website](https://retroarch.com?page=platforms). Or,
|
||||
- An SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other
|
||||
@@ -79,7 +78,7 @@ client, and will also create your ROM in the same place as your patch file.
|
||||
When the client launched automatically, SNI should have also automatically launched in the background. If this is its
|
||||
first time launching, you may be prompted to allow it to communicate through the Windows Firewall.
|
||||
|
||||
##### snes9x Multitroid
|
||||
##### snes9x-rr
|
||||
|
||||
1. Load your ROM file if it hasn't already been loaded.
|
||||
2. Click on the File menu and hover on **Lua Scripting**
|
||||
|
||||
@@ -2,7 +2,7 @@ import bsdiff4
|
||||
import yaml
|
||||
from typing import Optional
|
||||
import Utils
|
||||
from Patch import APDeltaPatch
|
||||
from worlds.Files import APDeltaPatch
|
||||
import os
|
||||
|
||||
|
||||
|
||||
@@ -333,8 +333,7 @@ class SoEWorld(World):
|
||||
switches.extend(('--available-fragments', str(self.available_fragments),
|
||||
'--required-fragments', str(self.required_fragments)))
|
||||
rom_file = get_base_rom_path()
|
||||
out_base = output_path(output_directory, f'AP_{self.world.seed_name}_P{self.player}_'
|
||||
f'{self.world.get_file_safe_player_name(self.player)}')
|
||||
out_base = output_path(output_directory, self.world.get_out_file_name_base(self.player))
|
||||
out_file = out_base + '.sfc'
|
||||
placement_file = out_base + '.txt'
|
||||
patch_file = out_base + '.apsoe'
|
||||
|
||||
@@ -7,37 +7,50 @@
|
||||
- Archipelago Mod for Subnautica
|
||||
from: [Subnautica Archipelago Mod Releases Page](https://github.com/Berserker66/ArchipelagoSubnauticaModSrc/releases)
|
||||
|
||||
## Installation Procedures
|
||||
## Installation Procedure
|
||||
|
||||
1. Install QModManager4 as per its instructions.
|
||||
|
||||
2. The folder you installed QModManager4 into will now have a /QMods directory. It might appear after a start of
|
||||
Subnautica. You can also create this folder yourself.
|
||||
2. The Subnautica game directory should now contain a `QMods` folder. Unpack the Archipelago Mod into this folder, so that `Subnautica/QMods/Archipelago/` is a valid path.
|
||||
|
||||
3. Unpack the Archipelago Mod into this folder, so that Subnautica/QMods/Archipelago/ is a valid path.
|
||||
|
||||
4. Start Subnautica. You should see a Connect Menu in the topleft of your main Menu.
|
||||
3. Start Subnautica. You should see a connect form with three text boxes in the top left of your main menu.
|
||||
|
||||
## Connecting
|
||||
|
||||
Using the Connect Menu in Subnautica's Main Menu you enter your connection info to connect to an Archipelago Multiworld.
|
||||
Menu points:
|
||||
Use the connect form in Subnautica's main menu to enter your connection information to connect to an Archipelago multiworld.
|
||||
Connection information consists of:
|
||||
- Host: the full url that you're trying to connect to, such as `archipelago.gg:38281`.
|
||||
- PlayerName: your name in the multiworld. Can also be called Slot Name and is the name you entered when creating your settings.
|
||||
- PlayerName: your name in the multiworld. Can also be called "slot name" and is the name you entered when creating your settings.
|
||||
- Password: optional password, leave blank if no password was set.
|
||||
|
||||
After the connection is made, start a new game. You should start to see Archipelago chat messages to appear, such as a message announcing that you joined the multiworld.
|
||||
|
||||
## Resuming
|
||||
|
||||
When loading a savegame it will automatically attempt to resume the connection that was active when the savegame was made.
|
||||
If that connection information is no longer valid, such as if the server's IP and/or port has changed, the Connect Menu will reappear after loading. Use the Connect Menu before or after loading the savegame to connect to the new instance.
|
||||
Savegames store their connection information and automatically attempt to reestablish the connection upon loading.
|
||||
If the connection information is no longer valid, such as if the server's IP and/or port have changed,
|
||||
you need to use the connect form on the main menu beforehand.
|
||||
|
||||
Warning: Currently it is not checked if this is the correct multiworld belonging to that savegame, please ensure that yourself beforehand.
|
||||
Warning: Currently it is not checked whether a loaded savegame belongs to the multiworld you are connecting to. Please ensure that yourself beforehand.
|
||||
|
||||
## Console Commands
|
||||
|
||||
The mod adds the following console commands:
|
||||
- `silent` toggles Archipelago chat messages appearing.
|
||||
- `deathlink` toggles death link.
|
||||
|
||||
To enable the console in Subnautica, press `F3` and `F8`, then uncheck "Disable Console" in the top left. Press `F3` and `F8` again to close the menus.
|
||||
To enter a console command, press `Enter`.
|
||||
|
||||
## Known Issues
|
||||
|
||||
- Do not attempt playing vanilla saves while the mod is installed, as the mod will override the scan information of the savegame.
|
||||
- When exiting to the main menu the mod's state is not properly reset. Loading a savegame from here will break various things.
|
||||
If you want to reload a save it is recommended you restart the game entirely.
|
||||
- Attempting to load a savegame containing no longer valid connection information without entering valid information on the main menu will hang on the loading screen.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you don't see the Connect Menu within the Main Menu, check that you see a file named `qmodmanager_log-Subnautica.txt` in the Subnautica game directory. If not,
|
||||
QModManager4 is not correctly installed, otherwise open it and look
|
||||
for `[Info : BepInEx] Loading [Archipelago`. If it doesn't show this, then
|
||||
If you don't see the connect form on the main menu screen, check whether you see a file named `qmodmanager_log-Subnautica.txt` in the Subnautica game directory. If not,
|
||||
QModManager4 is not correctly installed, otherwise open it and look for `Loading [Archipelago`. If the file doesn't contain this text, then
|
||||
QModManager4 didn't find the Archipelago mod, so check your paths.
|
||||
|
||||
@@ -91,6 +91,6 @@ class V6World(World):
|
||||
}
|
||||
}
|
||||
}
|
||||
filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_file_safe_player_name(self.player)}.apv6"
|
||||
filename = f"{self.world.get_out_file_name_base(self.player)}.apv6"
|
||||
with open(os.path.join(output_directory, filename), 'w') as f:
|
||||
json.dump(data, f)
|
||||
|
||||
Reference in New Issue
Block a user