Merge branch 'DoorDev' into CrossGenWork
This commit is contained in:
@@ -83,7 +83,7 @@ class World(object):
|
|||||||
set_player_attr('ganonstower_vanilla', True)
|
set_player_attr('ganonstower_vanilla', True)
|
||||||
set_player_attr('sewer_light_cone', self.mode[player] == 'standard')
|
set_player_attr('sewer_light_cone', self.mode[player] == 'standard')
|
||||||
set_player_attr('fix_trock_doors', self.shuffle[player] != 'vanilla' or self.mode[player] == 'inverted')
|
set_player_attr('fix_trock_doors', self.shuffle[player] != 'vanilla' or self.mode[player] == 'inverted')
|
||||||
set_player_attr('fix_skullwoods_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
set_player_attr('fix_skullwoods_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'] or self.doorShuffle[player] not in ['vanilla'])
|
||||||
set_player_attr('fix_palaceofdarkness_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
set_player_attr('fix_palaceofdarkness_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
||||||
set_player_attr('fix_trock_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
set_player_attr('fix_trock_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
||||||
set_player_attr('can_access_trock_eyebridge', None)
|
set_player_attr('can_access_trock_eyebridge', None)
|
||||||
@@ -450,17 +450,17 @@ class CollectionState(object):
|
|||||||
blocked.add(entrance.parent_region)
|
blocked.add(entrance.parent_region)
|
||||||
if color_type:
|
if color_type:
|
||||||
ccr[candidate] = color_type
|
ccr[candidate] = color_type
|
||||||
for ext in candidate.exits:
|
for ext in candidate.exits:
|
||||||
connect = ext.connected_region
|
connect = ext.connected_region
|
||||||
if connect in rrp and connect in ccr:
|
if connect in rrp and connect in ccr:
|
||||||
door = self.world.check_for_door(ext.name, player)
|
door = self.world.check_for_door(ext.name, player)
|
||||||
if door is not None and not door.blocked:
|
if door is not None and not door.blocked:
|
||||||
if ext.can_reach(self):
|
if ext.can_reach(self):
|
||||||
new_color = ccr[connect] | (ccr[candidate] & (door.crystal or CrystalBarrier.Either))
|
new_color = ccr[connect] | (ccr[candidate] & (door.crystal or CrystalBarrier.Either))
|
||||||
if new_color != ccr[connect]:
|
if new_color != ccr[connect]:
|
||||||
self.spread_crystal_access(candidate, new_color, rrp, ccr, player)
|
self.spread_crystal_access(candidate, new_color, rrp, ccr, player)
|
||||||
else:
|
else:
|
||||||
blocked.add(candidate)
|
blocked.add(candidate)
|
||||||
new_regions = len(rrp) > reachable_regions_count
|
new_regions = len(rrp) > reachable_regions_count
|
||||||
reachable_regions_count = len(rrp)
|
reachable_regions_count = len(rrp)
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ def link_doors(world, player):
|
|||||||
cross_dungeon(world, player)
|
cross_dungeon(world, player)
|
||||||
elif world.doorShuffle[player] == 'experimental':
|
elif world.doorShuffle[player] == 'experimental':
|
||||||
experiment(world, player)
|
experiment(world, player)
|
||||||
|
else:
|
||||||
|
logging.getLogger('').error('Invalid door shuffle setting: %s' % world.doorShuffle[player])
|
||||||
|
raise Exception('Invalid door shuffle setting: %s' % world.doorShuffle[player])
|
||||||
|
|
||||||
if world.doorShuffle[player] != 'vanilla':
|
if world.doorShuffle[player] != 'vanilla':
|
||||||
create_door_spoiler(world, player)
|
create_door_spoiler(world, player)
|
||||||
@@ -146,7 +149,8 @@ def vanilla_key_logic(world, player):
|
|||||||
analyze_dungeon(key_layout, world, player)
|
analyze_dungeon(key_layout, world, player)
|
||||||
world.key_logic[player][builder.name] = key_layout.key_logic
|
world.key_logic[player][builder.name] = key_layout.key_logic
|
||||||
last_key = None
|
last_key = None
|
||||||
validate_vanilla_key_logic(world, player)
|
if world.shuffle[player] == 'vanilla':
|
||||||
|
validate_vanilla_key_logic(world, player)
|
||||||
|
|
||||||
|
|
||||||
# some useful functions
|
# some useful functions
|
||||||
@@ -2023,18 +2027,19 @@ default_one_way_connections = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
# For crossed
|
# For crossed
|
||||||
compass_data = { # offset from 0x122e17, sram storage, write offset from compass_w_addr, 0 = jmp or # of nops
|
# offset from 0x122e17, sram storage, write offset from compass_w_addr, 0 = jmp or # of nops, dungeon_id
|
||||||
'Hyrule Castle': (0x1, 0xc0, 0x16, 0),
|
compass_data = {
|
||||||
'Eastern Palace': (0x1C, 0xc1, 0x28, 0),
|
'Hyrule Castle': (0x1, 0xc0, 0x16, 0, 0x02),
|
||||||
'Desert Palace': (0x35, 0xc2, 0x4a, 0),
|
'Eastern Palace': (0x1C, 0xc1, 0x28, 0, 0x04),
|
||||||
'Agahnims Tower': (0x51, 0xc3, 0x5c, 0),
|
'Desert Palace': (0x35, 0xc2, 0x4a, 0, 0x06),
|
||||||
'Swamp Palace': (0x6A, 0xc4, 0x7e, 0),
|
'Agahnims Tower': (0x51, 0xc3, 0x5c, 0, 0x08),
|
||||||
'Palace of Darkness': (0x83, 0xc5, 0xa4, 0),
|
'Swamp Palace': (0x6A, 0xc4, 0x7e, 0, 0x0a),
|
||||||
'Misery Mire': (0x9C, 0xc6, 0xca, 0),
|
'Palace of Darkness': (0x83, 0xc5, 0xa4, 0, 0x0c),
|
||||||
'Skull Woods': (0xB5, 0xc7, 0xf0, 0),
|
'Misery Mire': (0x9C, 0xc6, 0xca, 0, 0x0e),
|
||||||
'Ice Palace': (0xD0, 0xc8, 0x102, 0),
|
'Skull Woods': (0xB5, 0xc7, 0xf0, 0, 0x10),
|
||||||
'Tower of Hera': (0xEB, 0xc9, 0x114, 0),
|
'Ice Palace': (0xD0, 0xc8, 0x102, 0, 0x12),
|
||||||
'Thieves Town': (0x106, 0xca, 0x138, 0),
|
'Tower of Hera': (0xEB, 0xc9, 0x114, 0, 0x14),
|
||||||
'Turtle Rock': (0x11F, 0xcb, 0x15e, 0),
|
'Thieves Town': (0x106, 0xca, 0x138, 0, 0x16),
|
||||||
'Ganons Tower': (0x13A, 0xcc, 0x170, 2)
|
'Turtle Rock': (0x11F, 0xcb, 0x15e, 0, 0x18),
|
||||||
|
'Ganons Tower': (0x13A, 0xcc, 0x170, 2, 0x1a)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,8 +218,8 @@ def parse_arguments(argv, no_defaults=False):
|
|||||||
Select the rate at which the menu opens and closes.
|
Select the rate at which the menu opens and closes.
|
||||||
(default: %(default)s)
|
(default: %(default)s)
|
||||||
''')
|
''')
|
||||||
parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true')
|
parser.add_argument('--quickswap', default=defval(False), help='Enable quick item swapping with L and R.', action='store_true')
|
||||||
parser.add_argument('--disablemusic', help='Disables game music.', action='store_true')
|
parser.add_argument('--disablemusic', default=defval(False), help='Disables game music.', action='store_true')
|
||||||
parser.add_argument('--mapshuffle', default=defval(False), help='Maps are no longer restricted to their dungeons, but can be anywhere', action='store_true')
|
parser.add_argument('--mapshuffle', default=defval(False), help='Maps are no longer restricted to their dungeons, but can be anywhere', action='store_true')
|
||||||
parser.add_argument('--compassshuffle', default=defval(False), help='Compasses are no longer restricted to their dungeons, but can be anywhere', action='store_true')
|
parser.add_argument('--compassshuffle', default=defval(False), help='Compasses are no longer restricted to their dungeons, but can be anywhere', action='store_true')
|
||||||
parser.add_argument('--keyshuffle', default=defval(False), help='Small Keys are no longer restricted to their dungeons, but can be anywhere', action='store_true')
|
parser.add_argument('--keyshuffle', default=defval(False), help='Small Keys are no longer restricted to their dungeons, but can be anywhere', action='store_true')
|
||||||
|
|||||||
@@ -550,7 +550,7 @@ def link_entrances(world, player):
|
|||||||
('North Fairy Cave Exit', 'North Fairy Cave'),
|
('North Fairy Cave Exit', 'North Fairy Cave'),
|
||||||
('Lost Woods Hideout Exit', 'Lost Woods Hideout (top)'),
|
('Lost Woods Hideout Exit', 'Lost Woods Hideout (top)'),
|
||||||
('Lumberjack Tree Exit', 'Lumberjack Tree (top)'),
|
('Lumberjack Tree Exit', 'Lumberjack Tree (top)'),
|
||||||
(('Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'), 'Skull Woods Second Section (Drop)')]
|
(('Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)'), 'Skull Back Drop')]
|
||||||
|
|
||||||
if world.mode[player] == 'standard':
|
if world.mode[player] == 'standard':
|
||||||
# cannot move uncle cave
|
# cannot move uncle cave
|
||||||
@@ -587,7 +587,7 @@ def link_entrances(world, player):
|
|||||||
else:
|
else:
|
||||||
sw_hole_pool = dw_hole_entrances
|
sw_hole_pool = dw_hole_entrances
|
||||||
mandatory_dark_world.append('Skull Woods First Section Exit')
|
mandatory_dark_world.append('Skull Woods First Section Exit')
|
||||||
for target in ['Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']:
|
for target in ['Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']:
|
||||||
connect_entrance(world, sw_hole_pool.pop(), target, player)
|
connect_entrance(world, sw_hole_pool.pop(), target, player)
|
||||||
|
|
||||||
# sanctuary has to be in light world
|
# sanctuary has to be in light world
|
||||||
@@ -786,8 +786,8 @@ def link_entrances(world, player):
|
|||||||
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
|
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
|
||||||
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
|
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
|
||||||
|
|
||||||
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Woods Second Section (Drop)',
|
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
|
||||||
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']
|
'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
|
||||||
|
|
||||||
# tavern back door cannot be shuffled yet
|
# tavern back door cannot be shuffled yet
|
||||||
connect_doors(world, ['Tavern North'], ['Tavern'], player)
|
connect_doors(world, ['Tavern North'], ['Tavern'], player)
|
||||||
@@ -924,8 +924,8 @@ def link_entrances(world, player):
|
|||||||
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
|
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
|
||||||
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
|
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
|
||||||
|
|
||||||
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Woods Second Section (Drop)',
|
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
|
||||||
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']
|
'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
|
||||||
|
|
||||||
if world.mode[player] == 'standard':
|
if world.mode[player] == 'standard':
|
||||||
# cannot move uncle cave
|
# cannot move uncle cave
|
||||||
@@ -1627,8 +1627,8 @@ def link_inverted_entrances(world, player):
|
|||||||
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
|
hole_entrances = ['Kakariko Well Drop', 'Bat Cave Drop', 'North Fairy Cave Drop', 'Lost Woods Hideout Drop', 'Lumberjack Tree Tree', 'Sanctuary Grave',
|
||||||
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
|
'Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', 'Skull Woods Second Section Hole']
|
||||||
|
|
||||||
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Woods Second Section (Drop)',
|
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
|
||||||
'Skull Woods First Section (Left)', 'Skull Woods First Section (Right)', 'Skull Woods First Section (Top)']
|
'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
|
||||||
|
|
||||||
# tavern back door cannot be shuffled yet
|
# tavern back door cannot be shuffled yet
|
||||||
connect_doors(world, ['Tavern North'], ['Tavern'], player)
|
connect_doors(world, ['Tavern North'], ['Tavern'], player)
|
||||||
@@ -3780,8 +3780,8 @@ exit_ids = {'Links House Exit': (0x01, 0x00),
|
|||||||
'Lost Woods Hideout (top)': 0x7A,
|
'Lost Woods Hideout (top)': 0x7A,
|
||||||
'Lumberjack Tree (top)': 0x7F,
|
'Lumberjack Tree (top)': 0x7F,
|
||||||
'Sewer Drop': 0x81,
|
'Sewer Drop': 0x81,
|
||||||
'Skull Woods Second Section (Drop)': 0x79,
|
'Skull Back Drop': 0x79,
|
||||||
'Skull Woods First Section (Left)': 0x77,
|
'Skull Left Drop': 0x77,
|
||||||
'Skull Woods First Section (Right)': 0x78,
|
'Skull Pinball': 0x78,
|
||||||
'Skull Woods First Section (Top)': 0x76,
|
'Skull Pot Circle': 0x76,
|
||||||
'Pyramid': 0x7B}
|
'Pyramid': 0x7B}
|
||||||
|
|||||||
@@ -864,7 +864,8 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
|
|||||||
|
|
||||||
def cnt_avail_small_locations(free_locations, key_only, state, world, player):
|
def cnt_avail_small_locations(free_locations, key_only, state, world, player):
|
||||||
if not world.keyshuffle[player] and not world.retro[player]:
|
if not world.keyshuffle[player] and not world.retro[player]:
|
||||||
avail_chest_keys = min(free_locations - state.used_locations + state.used_smalls, state.key_locations - key_only)
|
bk_adj = 1 if state.big_key_opened and not state.big_key_special else 0
|
||||||
|
avail_chest_keys = min(free_locations - bk_adj, state.key_locations - key_only)
|
||||||
return max(0, avail_chest_keys + key_only - state.used_smalls)
|
return max(0, avail_chest_keys + key_only - state.used_smalls)
|
||||||
return state.key_locations - state.used_smalls
|
return state.key_locations - state.used_smalls
|
||||||
|
|
||||||
@@ -1146,20 +1147,22 @@ def val_mire(key_logic, world, player):
|
|||||||
|
|
||||||
|
|
||||||
def val_turtle(key_logic, world, player):
|
def val_turtle(key_logic, world, player):
|
||||||
val_rule(key_logic.door_rules['TR Hub NW'], 1)
|
# todo: check vanilla key logic when TR back doors are accessible
|
||||||
val_rule(key_logic.door_rules['TR Pokey 1 NW'], 2)
|
if world.shuffle[player] == 'vanilla' and world.mode[player] != 'inverted':
|
||||||
val_rule(key_logic.door_rules['TR Chain Chomps Down Stairs'], 3)
|
val_rule(key_logic.door_rules['TR Hub NW'], 1)
|
||||||
val_rule(key_logic.door_rules['TR Pokey 2 ES'], 6, True, 'Turtle Rock - Big Key Chest', 4, {'Turtle Rock - Big Key Chest'})
|
val_rule(key_logic.door_rules['TR Pokey 1 NW'], 2)
|
||||||
val_rule(key_logic.door_rules['TR Crystaroller Down Stairs'], 5)
|
val_rule(key_logic.door_rules['TR Chain Chomps Down Stairs'], 3)
|
||||||
val_rule(key_logic.door_rules['TR Dash Bridge WS'], 6)
|
val_rule(key_logic.door_rules['TR Pokey 2 ES'], 6, True, 'Turtle Rock - Big Key Chest', 4, {'Turtle Rock - Big Key Chest'})
|
||||||
assert world.get_location('Turtle Rock - Eye Bridge - Bottom Right', player) in key_logic.bk_restricted
|
val_rule(key_logic.door_rules['TR Crystaroller Down Stairs'], 5)
|
||||||
assert world.get_location('Turtle Rock - Eye Bridge - Top Left', player) in key_logic.bk_restricted
|
val_rule(key_logic.door_rules['TR Dash Bridge WS'], 6)
|
||||||
assert world.get_location('Turtle Rock - Eye Bridge - Top Right', player) in key_logic.bk_restricted
|
assert world.get_location('Turtle Rock - Eye Bridge - Bottom Right', player) in key_logic.bk_restricted
|
||||||
assert world.get_location('Turtle Rock - Eye Bridge - Bottom Left', player) in key_logic.bk_restricted
|
assert world.get_location('Turtle Rock - Eye Bridge - Top Left', player) in key_logic.bk_restricted
|
||||||
assert world.get_location('Turtle Rock - Boss', player) in key_logic.bk_restricted
|
assert world.get_location('Turtle Rock - Eye Bridge - Top Right', player) in key_logic.bk_restricted
|
||||||
assert world.get_location('Turtle Rock - Crystaroller Room', player) in key_logic.bk_restricted
|
assert world.get_location('Turtle Rock - Eye Bridge - Bottom Left', player) in key_logic.bk_restricted
|
||||||
assert world.get_location('Turtle Rock - Big Chest', player) in key_logic.bk_restricted
|
assert world.get_location('Turtle Rock - Boss', player) in key_logic.bk_restricted
|
||||||
assert len(key_logic.bk_restricted) == 7
|
assert world.get_location('Turtle Rock - Crystaroller Room', player) in key_logic.bk_restricted
|
||||||
|
assert world.get_location('Turtle Rock - Big Chest', player) in key_logic.bk_restricted
|
||||||
|
assert len(key_logic.bk_restricted) == 7
|
||||||
|
|
||||||
|
|
||||||
def val_ganons(key_logic, world, player):
|
def val_ganons(key_logic, world, player):
|
||||||
|
|||||||
3
Main.py
3
Main.py
@@ -23,7 +23,8 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
|
|||||||
from ItemList import generate_itempool, difficulties, fill_prizes
|
from ItemList import generate_itempool, difficulties, fill_prizes
|
||||||
from Utils import output_path, parse_player_names
|
from Utils import output_path, parse_player_names
|
||||||
|
|
||||||
__version__ = '0.0.7-pre'
|
__version__ = '0.0.9-pre'
|
||||||
|
|
||||||
|
|
||||||
def main(args, seed=None):
|
def main(args, seed=None):
|
||||||
if args.outputpath:
|
if args.outputpath:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import logging
|
|||||||
import random
|
import random
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
import re
|
||||||
|
|
||||||
from DungeonRandomizer import parse_arguments
|
from DungeonRandomizer import parse_arguments
|
||||||
from Main import main as DRMain
|
from Main import main as DRMain
|
||||||
@@ -14,6 +15,7 @@ def parse_yaml(txt):
|
|||||||
ret = {}
|
ret = {}
|
||||||
indents = {len(txt) - len(txt.lstrip(' ')): ret}
|
indents = {len(txt) - len(txt.lstrip(' ')): ret}
|
||||||
for line in txt.splitlines():
|
for line in txt.splitlines():
|
||||||
|
line = re.sub(r'#.*', '', line)
|
||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
name, val = line.split(':', 1)
|
name, val = line.split(':', 1)
|
||||||
|
|||||||
31
Rom.py
31
Rom.py
@@ -557,7 +557,7 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
# todo fix screen scrolling
|
# todo fix screen scrolling
|
||||||
|
|
||||||
if world.shuffle[player] not in ['insanity', 'insanity_legacy', 'madness_legacy'] and \
|
if world.shuffle[player] not in ['insanity', 'insanity_legacy', 'madness_legacy'] and \
|
||||||
exit.name in ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Skull Woods Final Section Exit', 'Ice Palace Exit', 'Misery Mire Exit',
|
exit.name in ['Eastern Palace Exit', 'Tower of Hera Exit', 'Thieves Town Exit', 'Ice Palace Exit', 'Misery Mire Exit',
|
||||||
'Palace of Darkness Exit', 'Swamp Palace Exit', 'Ganons Tower Exit', 'Desert Palace Exit (North)', 'Agahnims Tower Exit', 'Spiral Cave Exit (Top)',
|
'Palace of Darkness Exit', 'Swamp Palace Exit', 'Ganons Tower Exit', 'Desert Palace Exit (North)', 'Agahnims Tower Exit', 'Spiral Cave Exit (Top)',
|
||||||
'Superbunny Cave Exit (Bottom)', 'Turtle Rock Ledge Exit (East)']:
|
'Superbunny Cave Exit (Bottom)', 'Turtle Rock Ledge Exit (East)']:
|
||||||
# For exits that connot be reached from another, no need to apply offset fixes.
|
# For exits that connot be reached from another, no need to apply offset fixes.
|
||||||
@@ -608,16 +608,10 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
for paired_door in world.paired_doors[player]:
|
for paired_door in world.paired_doors[player]:
|
||||||
rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player))
|
rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player))
|
||||||
rom.write_bytes(paired_door.address_b(world, player), paired_door.rom_data_b(world, player))
|
rom.write_bytes(paired_door.address_b(world, player), paired_door.rom_data_b(world, player))
|
||||||
if world.fix_skullwoods_exit and world.shuffle in ['vanilla', 'simple', 'restricted', 'dungeonssimple']:
|
|
||||||
connect = world.get_entrance('Skull Woods Final Section', player).connected_region
|
# fix skull woods exit, if not fixed during exit patching
|
||||||
exit_name = None
|
if world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla':
|
||||||
for ext in connect.exits:
|
write_int16(rom, 0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8)
|
||||||
if ext.connected_region.name == 'Skull Woods Forest (West)':
|
|
||||||
exit_name = ext.name
|
|
||||||
break
|
|
||||||
if exit_name is not None and exit_name == 'Skull Woods Final Section Exit':
|
|
||||||
rom.write_int16(0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8)
|
|
||||||
# todo: fix other exits if ER enabled and similar situation happens
|
|
||||||
|
|
||||||
write_custom_shops(rom, world, player)
|
write_custom_shops(rom, world, player)
|
||||||
|
|
||||||
@@ -2102,8 +2096,19 @@ def compass_code_good(rom):
|
|||||||
|
|
||||||
def update_compasses(rom, world, player):
|
def update_compasses(rom, world, player):
|
||||||
layouts = world.dungeon_layouts[player]
|
layouts = world.dungeon_layouts[player]
|
||||||
|
# cmp XX : bne escape
|
||||||
|
# cpy 32 : bne escape
|
||||||
|
# brl .itemCounts
|
||||||
|
# c9 02 d0 eastern
|
||||||
|
# nop #2
|
||||||
|
new_code = [0x07, 0xC0, 0x32, 0xD0, 0x03, 0x82, 0xB9, 0x01, 0xC9, 0x02, 0xD0, 0x10, 0xEA, 0xEA]
|
||||||
|
rom.write_bytes(compass_w_addr + 8, new_code)
|
||||||
|
# 05 06 07 08
|
||||||
|
# C9 00 D0 02 80 04 C9 02 D0 15 C0 32 D0 03 82 B3 01
|
||||||
|
# C9 XX D0 07 C0 32 D0 03 82 B9 01 C9 02 D0 10 EA EA
|
||||||
|
|
||||||
for name, builder in layouts.items():
|
for name, builder in layouts.items():
|
||||||
digit_offset, sram_byte, write_offset, jmp_nop_flag = compass_data[name]
|
digit_offset, sram_byte, write_offset, jmp_nop_flag, dungeon_id = compass_data[name]
|
||||||
digit1 = builder.location_cnt // 10
|
digit1 = builder.location_cnt // 10
|
||||||
digit2 = builder.location_cnt % 10
|
digit2 = builder.location_cnt % 10
|
||||||
rom.write_byte(compass_r_addr+digit_offset, 0x90+digit1)
|
rom.write_byte(compass_r_addr+digit_offset, 0x90+digit1)
|
||||||
@@ -2128,6 +2133,8 @@ def update_compasses(rom, world, player):
|
|||||||
else:
|
else:
|
||||||
for i in range(0, jmp_nop_flag):
|
for i in range(0, jmp_nop_flag):
|
||||||
rom.write_byte(write_address+9+i, 0xea) # nop
|
rom.write_byte(write_address+9+i, 0xea) # nop
|
||||||
|
if builder.bk_provided:
|
||||||
|
rom.write_byte(compass_w_addr+6, dungeon_id)
|
||||||
|
|
||||||
|
|
||||||
InconvenientDungeonEntrances = {'Turtle Rock': 'Turtle Rock Main',
|
InconvenientDungeonEntrances = {'Turtle Rock': 'Turtle Rock Main',
|
||||||
|
|||||||
@@ -239,6 +239,8 @@ def create_rooms(world, player):
|
|||||||
world.get_room(0x61, player).swap(5, 6) # puts the Incognito Entrance at the end, so it can be deleted
|
world.get_room(0x61, player).swap(5, 6) # puts the Incognito Entrance at the end, so it can be deleted
|
||||||
world.get_room(0x62, player).swap(1, 4) # puts the exit at pos 1 - enables pos 3
|
world.get_room(0x62, player).swap(1, 4) # puts the exit at pos 1 - enables pos 3
|
||||||
world.get_room(0x77, player).swap(0, 1) # fixes Hera Lobby Key Stairs - entrance now at pos 0
|
world.get_room(0x77, player).swap(0, 1) # fixes Hera Lobby Key Stairs - entrance now at pos 0
|
||||||
|
if world.enemy_shuffle[player] != 'none':
|
||||||
|
world.get_room(0xc0, player).change(0, DoorKind.Normal) # fix this kill room if enemizer is on
|
||||||
|
|
||||||
|
|
||||||
class Room(object):
|
class Room(object):
|
||||||
|
|||||||
15
Rules.py
15
Rules.py
@@ -131,12 +131,12 @@ def global_rules(world, player):
|
|||||||
|
|
||||||
|
|
||||||
set_rule(world.get_location('Spike Cave', player), lambda state:
|
set_rule(world.get_location('Spike Cave', player), lambda state:
|
||||||
state.has('Hammer', player) and state.can_lift_rocks(player) and
|
state.has('Hammer', player) and state.can_lift_rocks(player) and
|
||||||
((state.has('Cape', player) and state.can_extend_magic(player, 16, True)) or
|
((state.has('Cape', player) and state.can_extend_magic(player, 16, True)) or
|
||||||
(state.has('Cane of Byrna', player) and
|
(state.has('Cane of Byrna', player) and
|
||||||
(state.can_extend_magic(player, 12, True) or
|
(state.can_extend_magic(player, 12, True) or
|
||||||
(state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4))))))
|
(state.world.can_take_damage and (state.has_Boots(player) or state.has_hearts(player, 4))))))
|
||||||
)
|
)
|
||||||
|
|
||||||
set_rule(world.get_location('Hookshot Cave - Top Right', player), lambda state: state.has('Hookshot', player))
|
set_rule(world.get_location('Hookshot Cave - Top Right', player), lambda state: state.has('Hookshot', player))
|
||||||
set_rule(world.get_location('Hookshot Cave - Top Left', player), lambda state: state.has('Hookshot', player))
|
set_rule(world.get_location('Hookshot Cave - Top Left', player), lambda state: state.has('Hookshot', player))
|
||||||
@@ -217,6 +217,7 @@ def global_rules(world, player):
|
|||||||
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize', player))
|
set_defeat_dungeon_boss_rule(world.get_location('Skull Woods - Prize', player))
|
||||||
|
|
||||||
# blind can't have the small key? - not necessarily true anymore - but likely still
|
# blind can't have the small key? - not necessarily true anymore - but likely still
|
||||||
|
set_rule(world.get_location('Thieves\' Town - Big Chest', player), lambda state: state.has('Hammer', player))
|
||||||
for entrance in ['Thieves Basement Block Path', 'Thieves Blocked Entry Path', 'Thieves Conveyor Block Path', 'Thieves Conveyor Bridge Block Path']:
|
for entrance in ['Thieves Basement Block Path', 'Thieves Blocked Entry Path', 'Thieves Conveyor Block Path', 'Thieves Conveyor Bridge Block Path']:
|
||||||
set_rule(world.get_entrance(entrance, player), lambda state: state.can_lift_rocks(player))
|
set_rule(world.get_entrance(entrance, player), lambda state: state.can_lift_rocks(player))
|
||||||
for location in ['Thieves\' Town - Blind\'s Cell', 'Thieves\' Town - Boss']:
|
for location in ['Thieves\' Town - Blind\'s Cell', 'Thieves\' Town - Boss']:
|
||||||
@@ -363,7 +364,7 @@ def global_rules(world, player):
|
|||||||
|
|
||||||
add_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
|
add_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
|
||||||
set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player)
|
set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player)
|
||||||
and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times
|
and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times
|
||||||
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop
|
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user