mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-28 12:43:26 -07:00
Merge remote-tracking branch 'upstream/main' into instruction_patch_kdl3
This commit is contained in:
@@ -207,6 +207,8 @@ class CommonContext:
|
||||
|
||||
finished_game: bool
|
||||
ready: bool
|
||||
team: typing.Optional[int]
|
||||
slot: typing.Optional[int]
|
||||
auth: typing.Optional[str]
|
||||
seed_name: typing.Optional[str]
|
||||
|
||||
|
||||
@@ -2198,7 +2198,7 @@ async def console(ctx: Context):
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser()
|
||||
defaults = Utils.get_options()["server_options"].as_dict()
|
||||
defaults = Utils.get_settings()["server_options"].as_dict()
|
||||
parser.add_argument('multidata', nargs="?", default=defaults["multidata"])
|
||||
parser.add_argument('--host', default=defaults["host"])
|
||||
parser.add_argument('--port', default=defaults["port"], type=int)
|
||||
|
||||
@@ -282,7 +282,7 @@ class SNESState(enum.IntEnum):
|
||||
|
||||
|
||||
def launch_sni() -> None:
|
||||
sni_path = Utils.get_options()["sni_options"]["sni_path"]
|
||||
sni_path = Utils.get_settings()["sni_options"]["sni_path"]
|
||||
|
||||
if not os.path.isdir(sni_path):
|
||||
sni_path = Utils.local_path(sni_path)
|
||||
@@ -654,7 +654,7 @@ async def game_watcher(ctx: SNIContext) -> None:
|
||||
|
||||
async def run_game(romfile: str) -> None:
|
||||
auto_start = typing.cast(typing.Union[bool, str],
|
||||
Utils.get_options()["sni_options"].get("snes_rom_start", True))
|
||||
Utils.get_settings()["sni_options"].get("snes_rom_start", True))
|
||||
if auto_start is True:
|
||||
import webbrowser
|
||||
webbrowser.open(romfile)
|
||||
|
||||
4
Utils.py
4
Utils.py
@@ -201,7 +201,7 @@ def cache_path(*path: str) -> str:
|
||||
def output_path(*path: str) -> str:
|
||||
if hasattr(output_path, 'cached_path'):
|
||||
return os.path.join(output_path.cached_path, *path)
|
||||
output_path.cached_path = user_path(get_options()["general_options"]["output_path"])
|
||||
output_path.cached_path = user_path(get_settings()["general_options"]["output_path"])
|
||||
path = os.path.join(output_path.cached_path, *path)
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
return path
|
||||
@@ -619,6 +619,8 @@ def get_fuzzy_results(input_word: str, wordlist: typing.Sequence[str], limit: ty
|
||||
|
||||
def open_filename(title: str, filetypes: typing.Sequence[typing.Tuple[str, typing.Sequence[str]]], suggest: str = "") \
|
||||
-> typing.Optional[str]:
|
||||
logging.info(f"Opening file input dialog for {title}.")
|
||||
|
||||
def run(*args: str):
|
||||
return subprocess.run(args, capture_output=True, text=True).stdout.split("\n", 1)[0] or None
|
||||
|
||||
|
||||
@@ -63,12 +63,13 @@ def process_multidata(compressed_multidata, files={}):
|
||||
game_data = games_package_schema.validate(game_data)
|
||||
game_data = {key: value for key, value in sorted(game_data.items())}
|
||||
game_data["checksum"] = data_package_checksum(game_data)
|
||||
game_data_package = GameDataPackage(checksum=game_data["checksum"],
|
||||
data=pickle.dumps(game_data))
|
||||
if original_checksum != game_data["checksum"]:
|
||||
raise Exception(f"Original checksum {original_checksum} != "
|
||||
f"calculated checksum {game_data['checksum']} "
|
||||
f"for game {game}.")
|
||||
|
||||
game_data_package = GameDataPackage(checksum=game_data["checksum"],
|
||||
data=pickle.dumps(game_data))
|
||||
decompressed_multidata["datapackage"][game] = {
|
||||
"version": game_data.get("version", 0),
|
||||
"checksum": game_data["checksum"],
|
||||
@@ -192,6 +193,8 @@ def uploads():
|
||||
res = upload_zip_to_db(zfile)
|
||||
except VersionException:
|
||||
flash(f"Could not load multidata. Wrong Version detected.")
|
||||
except Exception as e:
|
||||
flash(f"Could not load multidata. File may be corrupted or incompatible. ({e})")
|
||||
else:
|
||||
if res is str:
|
||||
return res
|
||||
|
||||
@@ -45,9 +45,6 @@
|
||||
# TODO
|
||||
#CACHE_TYPE: "simple"
|
||||
|
||||
# TODO
|
||||
#JSON_AS_ASCII: false
|
||||
|
||||
# Host Address. This is the address encoded into the patch that will be used for client auto-connect.
|
||||
#HOST_ADDRESS: archipelago.gg
|
||||
|
||||
|
||||
@@ -276,13 +276,14 @@ def generate_itempool(world):
|
||||
|
||||
# set up item pool
|
||||
additional_triforce_pieces = 0
|
||||
treasure_hunt_total = 0
|
||||
if multiworld.custom:
|
||||
pool, placed_items, precollected_items, clock_mode, treasure_hunt_count = (
|
||||
pool, placed_items, precollected_items, clock_mode, treasure_hunt_required = (
|
||||
make_custom_item_pool(multiworld, player))
|
||||
multiworld.rupoor_cost = min(multiworld.customitemarray[67], 9999)
|
||||
else:
|
||||
pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, additional_triforce_pieces = (
|
||||
get_pool_core(multiworld, player))
|
||||
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_required, treasure_hunt_total,
|
||||
additional_triforce_pieces) = get_pool_core(multiworld, player)
|
||||
|
||||
for item in precollected_items:
|
||||
multiworld.push_precollected(item_factory(item, world))
|
||||
@@ -337,7 +338,8 @@ def generate_itempool(world):
|
||||
if clock_mode:
|
||||
world.clock_mode = clock_mode
|
||||
|
||||
multiworld.worlds[player].treasure_hunt_count = treasure_hunt_count % 999
|
||||
multiworld.worlds[player].treasure_hunt_required = treasure_hunt_required % 999
|
||||
multiworld.worlds[player].treasure_hunt_total = treasure_hunt_total
|
||||
|
||||
dungeon_items = [item for item in get_dungeon_item_pool_player(world)
|
||||
if item.name not in multiworld.worlds[player].dungeon_local_item_names]
|
||||
@@ -590,7 +592,8 @@ def get_pool_core(world, player: int):
|
||||
placed_items = {}
|
||||
precollected_items = []
|
||||
clock_mode: str = ""
|
||||
treasure_hunt_count: int = 1
|
||||
treasure_hunt_required: int = 0
|
||||
treasure_hunt_total: int = 0
|
||||
|
||||
diff = difficulties[difficulty]
|
||||
pool.extend(diff.alwaysitems)
|
||||
@@ -679,20 +682,21 @@ def get_pool_core(world, player: int):
|
||||
if 'triforce_hunt' in goal:
|
||||
|
||||
if world.triforce_pieces_mode[player].value == TriforcePiecesMode.option_extra:
|
||||
triforce_pieces = world.triforce_pieces_available[player].value + world.triforce_pieces_extra[player].value
|
||||
treasure_hunt_total = (world.triforce_pieces_available[player].value
|
||||
+ world.triforce_pieces_extra[player].value)
|
||||
elif world.triforce_pieces_mode[player].value == TriforcePiecesMode.option_percentage:
|
||||
percentage = float(world.triforce_pieces_percentage[player].value) / 100
|
||||
triforce_pieces = int(round(world.triforce_pieces_required[player].value * percentage, 0))
|
||||
treasure_hunt_total = int(round(world.triforce_pieces_required[player].value * percentage, 0))
|
||||
else: # available
|
||||
triforce_pieces = world.triforce_pieces_available[player].value
|
||||
treasure_hunt_total = world.triforce_pieces_available[player].value
|
||||
|
||||
triforce_pieces = min(90, max(triforce_pieces, world.triforce_pieces_required[player].value))
|
||||
triforce_pieces = min(90, max(treasure_hunt_total, world.triforce_pieces_required[player].value))
|
||||
|
||||
pieces_in_core = min(extraitems, triforce_pieces)
|
||||
additional_pieces_to_place = triforce_pieces - pieces_in_core
|
||||
pool.extend(["Triforce Piece"] * pieces_in_core)
|
||||
extraitems -= pieces_in_core
|
||||
treasure_hunt_count = world.triforce_pieces_required[player].value
|
||||
treasure_hunt_required = world.triforce_pieces_required[player].value
|
||||
|
||||
for extra in diff.extras:
|
||||
if extraitems >= len(extra):
|
||||
@@ -733,7 +737,7 @@ def get_pool_core(world, player: int):
|
||||
place_item(key_location, "Small Key (Universal)")
|
||||
pool = pool[:-3]
|
||||
|
||||
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count,
|
||||
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_required, treasure_hunt_total,
|
||||
additional_pieces_to_place)
|
||||
|
||||
|
||||
@@ -749,7 +753,8 @@ def make_custom_item_pool(world, player):
|
||||
placed_items = {}
|
||||
precollected_items = []
|
||||
clock_mode: str = ""
|
||||
treasure_hunt_count: int = 1
|
||||
treasure_hunt_required: int = 0
|
||||
treasure_hunt_total: int = 0
|
||||
|
||||
def place_item(loc, item):
|
||||
assert loc not in placed_items, "cannot place item twice"
|
||||
@@ -844,7 +849,7 @@ def make_custom_item_pool(world, player):
|
||||
if "triforce" in world.goal[player]:
|
||||
pool.extend(["Triforce Piece"] * world.triforce_pieces_available[player])
|
||||
itemtotal += world.triforce_pieces_available[player]
|
||||
treasure_hunt_count = world.triforce_pieces_required[player]
|
||||
treasure_hunt_required = world.triforce_pieces_required[player]
|
||||
|
||||
if timer in ['display', 'timed', 'timed_countdown']:
|
||||
clock_mode = 'countdown' if timer == 'timed_countdown' else 'stopwatch'
|
||||
@@ -889,4 +894,4 @@ def make_custom_item_pool(world, player):
|
||||
pool.extend(['Nothing'] * (total_items_to_place - itemtotal))
|
||||
logging.warning(f"Pool was filled up with {total_items_to_place - itemtotal} Nothing's for player {player}")
|
||||
|
||||
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count)
|
||||
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_required)
|
||||
|
||||
@@ -433,7 +433,7 @@ def patch_enemizer(world, rom: LocalRom, enemizercli, output_directory):
|
||||
if multiworld.key_drop_shuffle[player]:
|
||||
key_drop_enemies = {
|
||||
0x4DA20, 0x4DA5C, 0x4DB7F, 0x4DD73, 0x4DDC3, 0x4DE07, 0x4E201,
|
||||
0x4E20A, 0x4E326, 0x4E4F7, 0x4E686, 0x4E70C, 0x4E7C8, 0x4E7FA
|
||||
0x4E20A, 0x4E326, 0x4E4F7, 0x4E687, 0x4E70C, 0x4E7C8, 0x4E7FA
|
||||
}
|
||||
for enemy in key_drop_enemies:
|
||||
if rom.read_byte(enemy) == 0x12:
|
||||
@@ -1269,7 +1269,7 @@ def patch_rom(world: MultiWorld, rom: LocalRom, player: int, enemized: bool):
|
||||
rom.write_int32(0x18020C, 0) # starting time (in frames, sint32)
|
||||
|
||||
# set up goals for treasure hunt
|
||||
rom.write_int16(0x180163, local_world.treasure_hunt_count)
|
||||
rom.write_int16(0x180163, local_world.treasure_hunt_required)
|
||||
rom.write_bytes(0x180165, [0x0E, 0x28]) # Triforce Piece Sprite
|
||||
rom.write_byte(0x180194, 1) # Must turn in triforced pieces (instant win not enabled)
|
||||
|
||||
@@ -1859,7 +1859,7 @@ def apply_oof_sfx(rom, oof: str):
|
||||
rom.write_bytes(0x12803A, oof_bytes)
|
||||
rom.write_bytes(0x12803A + len(oof_bytes), [0xEB, 0xEB])
|
||||
|
||||
#Enemizer patch: prevent Enemizer from overwriting $3188 in SPC memory with an unused sound effect ("WHAT")
|
||||
# Enemizer patch: prevent Enemizer from overwriting $3188 in SPC memory with an unused sound effect ("WHAT")
|
||||
rom.write_bytes(0x13000D, [0x00, 0x00, 0x00, 0x08])
|
||||
|
||||
|
||||
@@ -2482,16 +2482,16 @@ def write_strings(rom, world, player):
|
||||
tt['sign_ganon'] = 'Go find the Triforce pieces with your friends... Ganon is invincible!'
|
||||
else:
|
||||
tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!'
|
||||
if w.treasure_hunt_count > 1:
|
||||
if w.treasure_hunt_required > 1:
|
||||
tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\n" \
|
||||
"invisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\n" \
|
||||
"hidden in a hollow tree. If you bring\n%d Triforce pieces out of %d, I can reassemble it." % \
|
||||
(w.treasure_hunt_count, world.triforce_pieces_available[player])
|
||||
(w.treasure_hunt_required, w.treasure_hunt_total)
|
||||
else:
|
||||
tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\n" \
|
||||
"invisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\n" \
|
||||
"hidden in a hollow tree. If you bring\n%d Triforce piece out of %d, I can reassemble it." % \
|
||||
(w.treasure_hunt_count, world.triforce_pieces_available[player])
|
||||
(w.treasure_hunt_required, w.treasure_hunt_total)
|
||||
elif world.goal[player] in ['pedestal']:
|
||||
tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Your goal is at the pedestal.'
|
||||
tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.'
|
||||
@@ -2500,20 +2500,20 @@ def write_strings(rom, world, player):
|
||||
tt['ganon_fall_in'] = Ganon1_texts[local_random.randint(0, len(Ganon1_texts) - 1)]
|
||||
tt['ganon_fall_in_alt'] = 'You cannot defeat me until you finish your goal!'
|
||||
tt['ganon_phase_3_alt'] = 'Got wax in\nyour ears?\nI can not die!'
|
||||
if w.treasure_hunt_count > 1:
|
||||
if w.treasure_hunt_required > 1:
|
||||
if world.goal[player] == 'ganon_triforce_hunt' and world.players > 1:
|
||||
tt['sign_ganon'] = 'You need to find %d Triforce pieces out of %d with your friends to defeat Ganon.' % \
|
||||
(w.treasure_hunt_count, world.triforce_pieces_available[player])
|
||||
(w.treasure_hunt_required, w.treasure_hunt_total)
|
||||
elif world.goal[player] in ['ganon_triforce_hunt', 'local_ganon_triforce_hunt']:
|
||||
tt['sign_ganon'] = 'You need to find %d Triforce pieces out of %d to defeat Ganon.' % \
|
||||
(w.treasure_hunt_count, world.triforce_pieces_available[player])
|
||||
(w.treasure_hunt_required, w.treasure_hunt_total)
|
||||
else:
|
||||
if world.goal[player] == 'ganon_triforce_hunt' and world.players > 1:
|
||||
tt['sign_ganon'] = 'You need to find %d Triforce piece out of %d with your friends to defeat Ganon.' % \
|
||||
(w.treasure_hunt_count, world.triforce_pieces_available[player])
|
||||
(w.treasure_hunt_required, w.treasure_hunt_total)
|
||||
elif world.goal[player] in ['ganon_triforce_hunt', 'local_ganon_triforce_hunt']:
|
||||
tt['sign_ganon'] = 'You need to find %d Triforce piece out of %d to defeat Ganon.' % \
|
||||
(w.treasure_hunt_count, world.triforce_pieces_available[player])
|
||||
(w.treasure_hunt_required, w.treasure_hunt_total)
|
||||
|
||||
tt['kakariko_tavern_fisherman'] = TavernMan_texts[local_random.randint(0, len(TavernMan_texts) - 1)]
|
||||
|
||||
@@ -3021,7 +3021,7 @@ def get_base_rom_bytes(file_name: str = "") -> bytes:
|
||||
|
||||
|
||||
def get_base_rom_path(file_name: str = "") -> str:
|
||||
options = Utils.get_options()
|
||||
options = Utils.get_settings()
|
||||
if not file_name:
|
||||
file_name = options["lttp_options"]["rom_file"]
|
||||
if not os.path.exists(file_name):
|
||||
|
||||
@@ -554,8 +554,8 @@ def global_rules(multiworld: MultiWorld, player: int):
|
||||
set_rule(multiworld.get_location('Ganons Tower - Firesnake Room', player), lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 7) or
|
||||
((item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) or item_name_in_location_names(state, 'Small Key (Ganons Tower)', player, [('Ganons Tower - Firesnake Room', player)])) and state._lttp_has_key('Small Key (Ganons Tower)', player, 5)))
|
||||
for location in randomizer_room_chests:
|
||||
set_rule(multiworld.get_location(location, player), lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 8) or (
|
||||
item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) and state._lttp_has_key('Small Key (Ganons Tower)', player, 6)))
|
||||
set_rule(multiworld.get_location(location, player), lambda state: can_use_bombs(state, player) and (state._lttp_has_key('Small Key (Ganons Tower)', player, 8) or (
|
||||
item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) and state._lttp_has_key('Small Key (Ganons Tower)', player, 6))))
|
||||
|
||||
# Once again it is possible to need more than 7 keys...
|
||||
set_rule(multiworld.get_entrance('Ganons Tower (Tile Room) Key Door', player), lambda state: state.has('Fire Rod', player) and (state._lttp_has_key('Small Key (Ganons Tower)', player, 7) or (
|
||||
|
||||
@@ -30,7 +30,7 @@ def can_shoot_arrows(state: CollectionState, player: int) -> bool:
|
||||
|
||||
|
||||
def has_triforce_pieces(state: CollectionState, player: int) -> bool:
|
||||
count = state.multiworld.worlds[player].treasure_hunt_count
|
||||
count = state.multiworld.worlds[player].treasure_hunt_required
|
||||
return state.count('Triforce Piece', player) + state.count('Power Star', player) >= count
|
||||
|
||||
|
||||
|
||||
@@ -261,7 +261,8 @@ class ALTTPWorld(World):
|
||||
fix_fake_world: bool = True
|
||||
|
||||
clock_mode: str = ""
|
||||
treasure_hunt_count: int = 1
|
||||
treasure_hunt_required: int = 0
|
||||
treasure_hunt_total: int = 0
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.dungeon_local_item_names = set()
|
||||
|
||||
@@ -15,7 +15,7 @@ class TestDungeon(LTTPTestBase):
|
||||
self.remove_exits = [] # Block dungeon exits
|
||||
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
|
||||
self.multiworld.bombless_start[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = 2
|
||||
create_regions(self.multiworld, 1)
|
||||
self.multiworld.worlds[1].create_dungeons()
|
||||
create_shops(self.multiworld, 1)
|
||||
|
||||
@@ -33,22 +33,26 @@ class TestGanonsTower(TestDungeon):
|
||||
["Ganons Tower - Randomizer Room - Top Left", False, []],
|
||||
["Ganons Tower - Randomizer Room - Top Left", False, [], ['Hammer']],
|
||||
["Ganons Tower - Randomizer Room - Top Left", False, [], ['Hookshot']],
|
||||
["Ganons Tower - Randomizer Room - Top Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']],
|
||||
["Ganons Tower - Randomizer Room - Top Left", False, [], ['Bomb Upgrade (50)']],
|
||||
["Ganons Tower - Randomizer Room - Top Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']],
|
||||
|
||||
["Ganons Tower - Randomizer Room - Top Right", False, []],
|
||||
["Ganons Tower - Randomizer Room - Top Right", False, [], ['Hammer']],
|
||||
["Ganons Tower - Randomizer Room - Top Right", False, [], ['Hookshot']],
|
||||
["Ganons Tower - Randomizer Room - Top Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']],
|
||||
["Ganons Tower - Randomizer Room - Top Right", False, [], ['Bomb Upgrade (50)']],
|
||||
["Ganons Tower - Randomizer Room - Top Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']],
|
||||
|
||||
["Ganons Tower - Randomizer Room - Bottom Left", False, []],
|
||||
["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Hammer']],
|
||||
["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Hookshot']],
|
||||
["Ganons Tower - Randomizer Room - Bottom Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']],
|
||||
["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Bomb Upgrade (50)']],
|
||||
["Ganons Tower - Randomizer Room - Bottom Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']],
|
||||
|
||||
["Ganons Tower - Randomizer Room - Bottom Right", False, []],
|
||||
["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Hammer']],
|
||||
["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Hookshot']],
|
||||
["Ganons Tower - Randomizer Room - Bottom Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']],
|
||||
["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Bomb Upgrade (50)']],
|
||||
["Ganons Tower - Randomizer Room - Bottom Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']],
|
||||
|
||||
["Ganons Tower - Firesnake Room", False, []],
|
||||
["Ganons Tower - Firesnake Room", False, [], ['Hammer']],
|
||||
|
||||
@@ -16,7 +16,7 @@ class TestInverted(TestBase, LTTPTestBase):
|
||||
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
|
||||
self.multiworld.mode[1].value = 2
|
||||
self.multiworld.bombless_start[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = 2
|
||||
create_inverted_regions(self.multiworld, 1)
|
||||
self.world.create_dungeons()
|
||||
create_shops(self.multiworld, 1)
|
||||
|
||||
@@ -17,7 +17,7 @@ class TestInvertedMinor(TestBase, LTTPTestBase):
|
||||
self.multiworld.mode[1].value = 2
|
||||
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("minor_glitches")
|
||||
self.multiworld.bombless_start[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = 2
|
||||
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
|
||||
create_inverted_regions(self.multiworld, 1)
|
||||
self.world.create_dungeons()
|
||||
|
||||
@@ -17,7 +17,7 @@ class TestInvertedOWG(TestBase, LTTPTestBase):
|
||||
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("overworld_glitches")
|
||||
self.multiworld.mode[1].value = 2
|
||||
self.multiworld.bombless_start[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = 2
|
||||
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
|
||||
create_inverted_regions(self.multiworld, 1)
|
||||
self.world.create_dungeons()
|
||||
|
||||
@@ -13,7 +13,7 @@ class TestMinor(TestBase, LTTPTestBase):
|
||||
self.world_setup()
|
||||
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("minor_glitches")
|
||||
self.multiworld.bombless_start[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = 2
|
||||
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
|
||||
self.world.er_seed = 0
|
||||
self.world.create_regions()
|
||||
|
||||
@@ -14,7 +14,7 @@ class TestVanillaOWG(TestBase, LTTPTestBase):
|
||||
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
|
||||
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("overworld_glitches")
|
||||
self.multiworld.bombless_start[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = 2
|
||||
self.multiworld.worlds[1].er_seed = 0
|
||||
self.multiworld.worlds[1].create_regions()
|
||||
self.multiworld.worlds[1].create_items()
|
||||
|
||||
@@ -13,7 +13,7 @@ class TestVanilla(TestBase, LTTPTestBase):
|
||||
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("no_glitches")
|
||||
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
|
||||
self.multiworld.bombless_start[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = True
|
||||
self.multiworld.shuffle_capacity_upgrades[1].value = 2
|
||||
self.multiworld.worlds[1].er_seed = 0
|
||||
self.multiworld.worlds[1].create_regions()
|
||||
self.multiworld.worlds[1].create_items()
|
||||
|
||||
@@ -14,7 +14,7 @@ from .stages import get_locations_from_stage, get_normal_stage_exits, vanilla_st
|
||||
from .regions import get_region_info
|
||||
from .rules import CV64Rules
|
||||
from .data import iname, rname, ename
|
||||
from ..AutoWorld import WebWorld, World
|
||||
from worlds.AutoWorld import WebWorld, World
|
||||
from .aesthetics import randomize_lighting, shuffle_sub_weapons, rom_empty_breakables_flags, rom_sub_weapon_flags, \
|
||||
randomize_music, get_start_inventory_data, get_location_data, randomize_shop_prices, get_loading_zone_bytes, \
|
||||
get_countdown_numbers
|
||||
|
||||
@@ -521,7 +521,7 @@ rcon_port = args.rcon_port
|
||||
rcon_password = args.rcon_password if args.rcon_password else ''.join(
|
||||
random.choice(string.ascii_letters) for x in range(32))
|
||||
factorio_server_logger = logging.getLogger("FactorioServer")
|
||||
options = Utils.get_options()
|
||||
options = Utils.get_settings()
|
||||
executable = options["factorio_options"]["executable"]
|
||||
server_settings = args.server_settings if args.server_settings \
|
||||
else options["factorio_options"].get("server_settings", None)
|
||||
|
||||
@@ -3,7 +3,7 @@ from dataclasses import dataclass
|
||||
from schema import And, Schema
|
||||
|
||||
from Options import Toggle, Choice, DefaultOnToggle, Range, PerGameCommonOptions, StartInventoryPool, OptionDict
|
||||
from worlds.lingo.items import TRAP_ITEMS
|
||||
from .items import TRAP_ITEMS
|
||||
|
||||
|
||||
class ShuffleDoors(Choice):
|
||||
|
||||
@@ -78,13 +78,16 @@ def get_progressive_item_id(name: str):
|
||||
def load_static_data_from_file():
|
||||
global PAINTING_ENTRANCES, PAINTING_EXITS
|
||||
|
||||
from . import datatypes
|
||||
from Utils import safe_builtins
|
||||
|
||||
class RenameUnpickler(pickle.Unpickler):
|
||||
def find_class(self, module, name):
|
||||
renamed_module = module
|
||||
if module == "datatypes":
|
||||
renamed_module = "worlds.lingo.datatypes"
|
||||
|
||||
return super(RenameUnpickler, self).find_class(renamed_module, name)
|
||||
if module in ("worlds.lingo.datatypes", "datatypes"):
|
||||
return getattr(datatypes, name)
|
||||
elif module == "builtins" and name in safe_builtins:
|
||||
return getattr(safe_builtins, name)
|
||||
raise pickle.UnpicklingError(f"global '{module}.{name}' is forbidden")
|
||||
|
||||
file = pkgutil.get_data(__name__, os.path.join("data", "generated.dat"))
|
||||
pickdata = RenameUnpickler(BytesIO(file)).load()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from worlds.lingo.static_logic import HASHES
|
||||
from worlds.lingo.utils.pickle_static_data import hash_file
|
||||
from ..static_logic import HASHES
|
||||
from ..utils.pickle_static_data import hash_file
|
||||
|
||||
|
||||
class TestDatafile(unittest.TestCase):
|
||||
|
||||
@@ -2,8 +2,8 @@ from copy import deepcopy
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
from BaseClasses import CollectionState, PlandoOptions
|
||||
from worlds.generic import PlandoConnection
|
||||
from .options import ShufflePortals
|
||||
from ..generic import PlandoConnection
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import MessengerWorld
|
||||
|
||||
@@ -49,7 +49,7 @@ def set_rules(tloz_world: "TLoZWorld"):
|
||||
for location in level.locations:
|
||||
add_rule(world.get_location(location.name, player),
|
||||
lambda state: state.has_group("candles", player)
|
||||
or (state.has("Magical Rod", player) and state.has("Book", player)))
|
||||
or (state.has("Magical Rod", player) and state.has("Book of Magic", player)))
|
||||
|
||||
# Everything from 5 on up has gaps
|
||||
for level in tloz_world.levels[5:]:
|
||||
@@ -84,6 +84,11 @@ def set_rules(tloz_world: "TLoZWorld"):
|
||||
add_rule(world.get_location(location, player),
|
||||
lambda state: state.has_group("swords", player) or state.has("Magical Rod", player))
|
||||
|
||||
# Candle access for Level 8
|
||||
for location in tloz_world.levels[8].locations:
|
||||
add_rule(world.get_location(location.name, player),
|
||||
lambda state: state.has_group("candles", player))
|
||||
|
||||
add_rule(world.get_location("Level 8 Item (Magical Key)", player),
|
||||
lambda state: state.has("Bow", player) and state.has_group("arrows", player))
|
||||
if options.ExpandedPool:
|
||||
|
||||
Reference in New Issue
Block a user