Merge remote-tracking branch 'remotes/door_rando/DoorDev' into Dev

This commit is contained in:
compiling
2020-01-11 09:17:41 +11:00
15 changed files with 213 additions and 43 deletions
+67 -5
View File
@@ -2,7 +2,9 @@ import copy
from enum import Enum, unique
import logging
import json
from collections import OrderedDict
from collections import OrderedDict, deque
from EntranceShuffle import door_addresses
from _vendor.collections_extended import bag
from EntranceShuffle import door_addresses
from Utils import int16_as_bytes
@@ -373,6 +375,7 @@ class CollectionState(object):
self.prog_items = bag()
self.world = parent
self.reachable_regions = {player: set() for player in range(1, parent.players + 1)}
self.colored_regions = {player: {} for player in range(1, parent.players + 1)}
self.events = []
self.path = {}
self.locations_checked = set()
@@ -384,6 +387,7 @@ class CollectionState(object):
player_regions = self.world.get_regions(player)
self.stale[player] = False
rrp = self.reachable_regions[player]
ccr = self.colored_regions[player]
new_regions = True
reachable_regions_count = len(rrp)
while new_regions:
@@ -391,13 +395,53 @@ class CollectionState(object):
for candidate in player_regions:
if candidate.can_reach_private(self):
rrp.add(candidate)
if candidate.type == RegionType.Dungeon:
c_switch_present = False
for ext in candidate.exits:
door = self.world.check_for_door(ext.name, player)
if door is not None and door.crystal == CrystalBarrier.Either:
c_switch_present = True
if c_switch_present:
ccr[candidate] = CrystalBarrier.Either
self.spread_crystal_access(candidate, CrystalBarrier.Either, rrp, ccr, player)
else:
for entrance in candidate.entrances:
door = self.world.check_for_door(entrance.name, player)
if door is None or entrance.parent_region.type != RegionType.Dungeon:
ccr[candidate] = CrystalBarrier.Orange
if entrance.parent_region in ccr.keys():
color_type = ccr[entrance.parent_region]
current_type = ccr[candidate] if candidate in ccr.keys() else None
ccr[candidate] = color_type if current_type is None or color_type == current_type else CrystalBarrier.Either
new_regions = len(rrp) > reachable_regions_count
reachable_regions_count = len(rrp)
def spread_crystal_access(self, region, crystal, rrp, ccr, player):
queue = deque([(region, crystal)])
visited = set()
while len(queue) > 0:
region, crystal = queue.popleft()
visited.add(region)
for ext in region.exits:
connect = ext.connected_region
if connect not in visited and connect is not None and connect.type == RegionType.Dungeon:
if connect in rrp and ext.can_reach(self) and connect:
door = self.world.check_for_door(ext.name, player)
current_crystal = ccr[connect]
if door is not None and not door.blocked and current_crystal != crystal and current_crystal != CrystalBarrier.Either:
if door.crystal in [CrystalBarrier.Either, CrystalBarrier.Null]:
ccr[connect] = crystal
queue.append((connect, crystal))
else:
queue.append((connect, door.crystal))
if door.crystal != current_crystal:
ccr[connect] = CrystalBarrier.Either
def copy(self):
ret = CollectionState(self.world)
ret.prog_items = self.prog_items.copy()
ret.reachable_regions = {player: copy.copy(self.reachable_regions[player]) for player in range(1, self.world.players + 1)}
ret.colored_regions = {player: copy.copy(self.colored_regions[player]) for player in range(1, self.world.players + 1)}
ret.events = copy.copy(self.events)
ret.path = copy.copy(self.path)
ret.locations_checked = copy.copy(self.locations_checked)
@@ -418,6 +462,15 @@ class CollectionState(object):
return spot.can_reach(self)
def sweep_for_crystal_access(self):
for player, rrp in self.reachable_regions.items():
dungeon_regions = [x for x in rrp if x.type == RegionType.Dungeon]
ccr = self.colored_regions[player]
for region in dungeon_regions:
if region in ccr.keys():
self.spread_crystal_access(region, ccr[region], rrp, ccr, player)
self.stale[player] = True
def sweep_for_events(self, key_only=False, locations=None):
# this may need improvement
if locations is None:
@@ -435,6 +488,18 @@ class CollectionState(object):
self.collect(event.item, True, event)
new_locations = len(reachable_events) > checked_locations
checked_locations = len(reachable_events)
if new_locations:
self.sweep_for_crystal_access()
def can_reach_blue(self, region, player):
if region not in self.colored_regions[player].keys():
return False
return self.colored_regions[player][region] in [CrystalBarrier.Blue, CrystalBarrier.Either]
def can_reach_orange(self, region, player):
if region not in self.colored_regions[player].keys():
return False
return self.colored_regions[player][region] in [CrystalBarrier.Orange, CrystalBarrier.Either]
def _do_not_flood_the_keys(self, reachable_events):
adjusted_checks = list(reachable_events)
@@ -721,7 +786,7 @@ class CollectionState(object):
class RegionType(Enum):
LightWorld = 1
DarkWorld = 2
Cave = 3 # Also includes Houses
Cave = 3 # Also includes Houses
Dungeon = 4
@property
@@ -1277,7 +1342,6 @@ class Shop(object):
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked):
self.region = region
self.room_id = room_id
self.default_door_id = default_door_id
self.type = type
self.inventory = [None, None, None]
self.shopkeeper_config = shopkeeper_config
@@ -1297,8 +1361,6 @@ class Shop(object):
config = self.item_count
if len(entrances) == 1 and entrances[0].name in door_addresses:
door_id = door_addresses[entrances[0].name][0]+1
elif self.default_door_id is not None:
door_id = self.default_door_id
else:
door_id = 0
config |= 0x40 # ignore door id
+10 -5
View File
@@ -734,6 +734,7 @@ def reassign_boss(boss_region, boss_key, builder, gt, world, player):
def experiment(world, player):
# print_wiki_doors(dungeon_regions, world, player)
cross_dungeon(world, player)
@@ -750,8 +751,12 @@ def convert_to_sectors(region_names, world, player):
matching_sectors = []
while len(exits) > 0:
ext = exits.pop()
if ext.connected_region is not None:
connect_region = ext.connected_region
door = world.check_for_door(ext.name, player)
if ext.connected_region is not None or door is not None and door.controller is not None:
if door is not None and door.controller is not None:
connect_region = world.get_entrance(door.controller.name, player).parent_region
else:
connect_region = ext.connected_region
if connect_region not in region_chunk and connect_region in region_list:
region_list.remove(connect_region)
region_chunk.append(connect_region)
@@ -763,7 +768,6 @@ def convert_to_sectors(region_names, world, player):
if existing not in matching_sectors:
matching_sectors.append(existing)
else:
door = world.check_for_door(ext.name, player)
if door is not None and door.controller is None and door.dest is None:
outstanding_doors.append(door)
sector = Sector()
@@ -1034,7 +1038,7 @@ def reassign_key_doors(builder, proposal, world, player):
room.delete(d.doorListPos)
else:
if len(room.doorList) > 1:
room.mirror(d.doorListPos)
room.mirror(d.doorListPos) # todo: I don't think this works for crossed - maybe it will
else:
room.delete(d.doorListPos)
d.smallKey = False
@@ -1350,7 +1354,6 @@ logical_connections = [
('Thieves Conveyor Block Path', 'Thieves Conveyor Bridge'),
('Ice Cross Bottom Push Block Left', 'Ice Floor Switch'),
('Ice Cross Right Push Block Top', 'Ice Bomb Drop'),
('Ice Cross Top Push Block Left', 'Ice Floor Switch'),
('Ice Big Key Push Block', 'Ice Dead End'),
('Ice Bomb Jump Ledge Orange Barrier', 'Ice Bomb Jump Catwalk'),
('Ice Bomb Jump Catwalk Orange Barrier', 'Ice Bomb Jump Ledge'),
@@ -1536,6 +1539,8 @@ falldown_pits = [
('Ice Backwards Room Hole', 'Ice Fairy'),
('Ice Antechamber Hole', 'Ice Boss'),
('Mire Attic Hint Hole', 'Mire BK Chest Ledge'),
('Mire Torches Top Holes', 'Mire Conveyor Barrier'),
('Mire Torches Bottom Holes', 'Mire Warping Pool'),
('GT Bob\'s Room Hole', 'GT Ice Armos'),
('GT Falling Torches Hole', 'GT Staredown'),
('GT Moldorm Hole', 'GT Moldorm Pit')
+11 -6
View File
@@ -616,7 +616,7 @@ def create_doors(world, player):
create_door(player, 'Ice Cross Bottom Push Block Right', Lgcl), # dynamic
create_door(player, 'Ice Cross Right Push Block Top', Lgcl),
create_door(player, 'Ice Cross Right Push Block Bottom', Lgcl), # dynamic
create_door(player, 'Ice Cross Top Push Block Left', Lgcl),
create_door(player, 'Ice Cross Top Push Block Bottom', Lgcl), # dynamic
create_door(player, 'Ice Cross Top Push Block Right', Lgcl), # dynamic
create_door(player, 'Ice Cross Bottom SE', Nrml).dir(So, 0x1e, Right, High).pos(3),
create_door(player, 'Ice Cross Right ES', Nrml).dir(Ea, 0x1e, Bot, High).trap(0x4).pos(0),
@@ -789,8 +789,10 @@ def create_doors(world, player):
create_door(player, 'Mire Warping Pool Warp', Warp),
create_door(player, 'Mire Torches Top Down Stairs', Sprl).dir(Dn, 0x97, 0, HTH).ss(A, 0x11, 0xb0, True).kill(),
create_door(player, 'Mire Torches Top SW', Intr).dir(So, 0x97, Left, High).pos(1),
create_door(player, 'Mire Torches Bottom Holes', Hole),
create_door(player, 'Mire Torches Bottom NW', Intr).dir(No, 0x97, Left, High).pos(1),
create_door(player, 'Mire Torches Bottom WS', Intr).dir(We, 0x97, Bot, High).pos(0),
create_door(player, 'Mire Torches Top Holes', Hole),
create_door(player, 'Mire Attic Hint ES', Intr).dir(Ea, 0x97, Bot, High).pos(0),
create_door(player, 'Mire Attic Hint Hole', Hole),
create_door(player, 'Mire Dark Shooters Up Stairs', Sprl).dir(Up, 0x93, 0, LTH).ss(A, 0x32, 0xec),
@@ -900,7 +902,7 @@ def create_doors(world, player):
create_door(player, 'GT Torch EN', Intr).dir(Ea, 0x8c, Top, High).small_key().pos(2),
create_door(player, 'GT Hope Room WN', Intr).dir(We, 0x8c, Top, High).small_key().pos(2),
create_door(player, 'GT Torch SW', Intr).dir(So, 0x8c, Left, High).no_exit().pos(1),
create_door(player, 'GT Big Chest NW', Intr).dir(So, 0x8c, Left, High).pos(1),
create_door(player, 'GT Big Chest NW', Intr).dir(No, 0x8c, Left, High).pos(1),
create_door(player, 'GT Blocked Stairs Down Stairs', Sprl).dir(Dn, 0x8c, 3, HTH).ss(Z, 0x12, 0x40, True, True).kill(),
create_door(player, 'GT Blocked Stairs Block Path', Lgcl),
create_door(player, 'GT Big Chest SW', Nrml).dir(So, 0x8c, Left, High).pos(4),
@@ -1004,11 +1006,11 @@ def create_doors(world, player):
create_door(player, 'GT Gauntlet 2 EN', Intr).dir(Ea, 0x5d, Top, High).pos(2),
create_door(player, 'GT Gauntlet 2 SW', Intr).dir(So, 0x5d, Left, High).pos(0),
create_door(player, 'GT Gauntlet 3 NW', Intr).dir(No, 0x5d, Left, High).pos(0),
create_door(player, 'GT Gauntlet 3 SW', Nrml).dir(So, 0x5d, Left, High).pos(1),
create_door(player, 'GT Gauntlet 4 NW', Nrml).dir(No, 0x6d, Left, High).pos(0),
create_door(player, 'GT Gauntlet 3 SW', Nrml).dir(So, 0x5d, Left, High).trap(0x2).pos(1),
create_door(player, 'GT Gauntlet 4 NW', Nrml).dir(No, 0x6d, Left, High).trap(0x4).pos(0),
create_door(player, 'GT Gauntlet 4 SW', Intr).dir(So, 0x6d, Left, High).pos(1),
create_door(player, 'GT Gauntlet 5 NW', Intr).dir(No, 0x6d, Left, High).pos(1),
create_door(player, 'GT Gauntlet 5 WS', Nrml).dir(We, 0x6d, Bot, High).pos(2),
create_door(player, 'GT Gauntlet 5 WS', Nrml).dir(We, 0x6d, Bot, High).trap(0x1).pos(2),
create_door(player, 'GT Beam Dash ES', Nrml).dir(Ea, 0x6c, Bot, High).pos(2).kill(),
create_door(player, 'GT Beam Dash WS', Intr).dir(We, 0x6c, Bot, High).pos(0),
create_door(player, 'GT Lanmolas 2 ES', Intr).dir(Ea, 0x6c, Bot, High).pos(0),
@@ -1084,11 +1086,12 @@ def create_doors(world, player):
world.get_door('Hera Startile Wide Holes', player).c_switch()
world.get_door('PoD Arena Main SW', player).c_switch()
world.get_door('PoD Arena Bonk Path', player).c_switch()
world.get_door('PoD Arena Bridge SE', player).c_switch()
world.get_door('PoD Arena Bridge Drop Down', player).c_switch()
world.get_door('PoD Arena Main Orange Barrier', player).barrier(CrystalBarrier.Orange)
# maybe you can cross this way with blue up??
world.get_door('PoD Arena Main Crystal Path', player).barrier(CrystalBarrier.Blue)
world.get_door('PoD Arena Crystals E', player).barrier(CrystalBarrier.Blue)
world.get_door('PoD Arena Crystal Path', player).barrier(CrystalBarrier.Blue)
world.get_door('PoD Sexy Statue W', player).c_switch()
world.get_door('PoD Sexy Statue NW', player).c_switch()
@@ -1185,6 +1188,7 @@ def create_doors(world, player):
world.get_door('GT Hookshot Entry Blue Barrier', player).barrier(CrystalBarrier.Blue)
world.get_door('GT Double Switch Orange Barrier', player).barrier(CrystalBarrier.Orange)
world.get_door('GT Double Switch Orange Barrier 2', player).barrier(CrystalBarrier.Orange)
world.get_door('GT Double Switch Orange Path', player).barrier(CrystalBarrier.Orange)
world.get_door('GT Double Switch Key Orange Path', player).barrier(CrystalBarrier.Orange)
world.get_door('GT Double Switch Key Blue Path', player).barrier(CrystalBarrier.Blue)
world.get_door('GT Double Switch Blue Barrier', player).barrier(CrystalBarrier.Blue)
@@ -1195,6 +1199,7 @@ def create_doors(world, player):
east_controller = world.get_door('Ice Cross Right ES', player)
controller_door(south_controller, world.get_door('Ice Cross Left Push Block', player))
controller_door(south_controller, world.get_door('Ice Cross Right Push Block Bottom', player))
controller_door(south_controller, world.get_door('Ice Cross Top Push Block Bottom', player))
controller_door(east_controller, world.get_door('Ice Cross Bottom Push Block Right', player))
controller_door(east_controller, world.get_door('Ice Cross Top Push Block Right', player))
+2 -2
View File
@@ -1128,7 +1128,7 @@ def assign_crystal_switch_sectors(dungeon_map, crystal_switches, assign_one=Fals
assign_sector(random.choice(list(crystal_switches)), builder, crystal_switches)
return crystal_switches
sector_list = list(crystal_switches)
choices = random.choices(sector_list, k=len(population))
choices = random.sample(sector_list, k=len(population))
for i, choice in enumerate(choices):
builder = dungeon_map[population[i]]
assign_sector(choice, builder, crystal_switches)
@@ -1583,7 +1583,7 @@ dungeon_boss_sectors = {
'Palace of Darkness': ['PoD Boss'],
'Swamp Palace': ['Swamp Boss'],
'Skull Woods': ['Skull Boss'],
'Thieves Town': ['Thieves Attic Window', 'Thieves Blind\'s Cell', 'Thieves Boss'],
'Thieves Town': ['Thieves Blind\'s Cell', 'Thieves Boss'],
'Ice Palace': ['Ice Boss'],
'Misery Mire': ['Mire Boss'],
'Turtle Rock': ['TR Boss'],
+3 -3
View File
@@ -303,7 +303,7 @@ def guiMain(args=None):
shuffleFrame = Frame(drowDownFrame)
shuffleVar = StringVar()
shuffleVar.set('full')
shuffleVar.set('vanilla')
shuffleOptionMenu = OptionMenu(shuffleFrame, shuffleVar, 'vanilla', 'simple', 'restricted', 'full', 'crossed', 'insanity', 'restricted_legacy', 'full_legacy', 'madness_legacy', 'insanity_legacy', 'dungeonsfull', 'dungeonssimple')
shuffleOptionMenu.pack(side=RIGHT)
shuffleLabel = Label(shuffleFrame, text='Entrance shuffle algorithm')
@@ -311,8 +311,8 @@ def guiMain(args=None):
doorShuffleFrame = Frame(drowDownFrame)
doorShuffleVar = StringVar()
doorShuffleVar.set('vanilla')
doorShuffleOptionMenu = OptionMenu(doorShuffleFrame, doorShuffleVar, 'vanilla', 'basic', 'crosssed', 'experimental')
doorShuffleVar.set('basic')
doorShuffleOptionMenu = OptionMenu(doorShuffleFrame, doorShuffleVar, 'vanilla', 'basic', 'crossed', 'experimental')
doorShuffleOptionMenu.pack(side=RIGHT)
doorShuffleLabel = Label(doorShuffleFrame, text='Door shuffle algorithm')
doorShuffleLabel.pack(side=LEFT)
+17 -13
View File
@@ -118,9 +118,9 @@ def analyze_dungeon(key_layout, world, player):
raw_avail = chest_keys + len(key_counter.key_only_locations)
available = raw_avail - key_counter.used_keys
possible_smalls = count_unique_small_doors(key_counter, key_layout.flat_prop)
avail_bigs = count_unique_big_doors(key_counter)
avail_bigs = exist_relevant_big_doors(key_counter, key_layout)
if not key_counter.big_key_opened:
if chest_keys == count_locations_big_optional(key_counter.free_locations) and available <= possible_smalls and avail_bigs == 0:
if chest_keys == count_locations_big_optional(key_counter.free_locations) and available <= possible_smalls and not avail_bigs:
key_logic.bk_restricted.update(filter_big_chest(key_counter.free_locations))
if not key_counter.big_key_opened and big_chest_in_locations(key_counter.free_locations):
key_logic.sm_restricted.update(find_big_chest_locations(key_counter.free_locations))
@@ -318,6 +318,7 @@ def create_rule(key_counter, prev_counter, key_layout, world, player):
available = raw_avail - key_counter.used_keys
possible_smalls = count_unique_small_doors(key_counter, key_layout.flat_prop)
required_keys = min(available, possible_smalls) + key_counter.used_keys
# required_keys = key_counter.used_keys + 1 # this sometimes makes more sense
# if prev_avail < required_keys:
# required_keys = prev_avail + prev_counter.used_keys
# return DoorRules(required_keys)
@@ -487,15 +488,16 @@ def count_unique_small_doors(key_counter, proposal):
return cnt
def count_unique_big_doors(key_counter):
cnt = 0
counted = set()
for door in key_counter.child_doors:
if door.bigKey and door not in counted:
cnt += 1
counted.add(door)
counted.add(door.dest)
return cnt
def exist_relevant_big_doors(key_counter, key_layout):
bk_counter = find_counter(key_counter.open_doors, True, key_layout, False)
if bk_counter is not None:
diff = dict_difference(bk_counter.free_locations, key_counter.free_locations)
if len(diff) > 0:
return True
diff = dict_difference(bk_counter.key_only_locations, key_counter.key_only_locations)
if len(diff) > 0:
return True
return False
def count_locations_big_optional(locations, bk=False):
@@ -788,7 +790,7 @@ def state_id(state, flat_proposal):
return s_id
def find_counter(opened_doors, bk_hint, key_layout):
def find_counter(opened_doors, bk_hint, key_layout, raise_on_error=True):
counter = find_counter_hint(opened_doors, bk_hint, key_layout)
if counter is not None:
return counter
@@ -801,7 +803,9 @@ def find_counter(opened_doors, bk_hint, key_layout):
counter = find_counter_hint(dict.fromkeys(more_doors), bk_hint, key_layout)
if counter is not None:
return counter
raise Exception('Unable to find door permutation. Init CID: %s' % counter_id(opened_doors, bk_hint, key_layout.flat_prop))
if raise_on_error:
raise Exception('Unable to find door permutation. Init CID: %s' % counter_id(opened_doors, bk_hint, key_layout.flat_prop))
return None
def find_counter_hint(opened_doors, bk_hint, key_layout):
+2
View File
@@ -361,6 +361,7 @@ def create_playthrough(world):
logging.getLogger('').debug('Building up collection spheres.')
while sphere_candidates:
state.sweep_for_events(key_only=True)
state.sweep_for_crystal_access()
sphere = []
# build up spheres of collection radius. Everything in each sphere is independent from each other in dependencies and only depends on lower spheres
@@ -422,6 +423,7 @@ def create_playthrough(world):
collection_spheres = []
while required_locations:
state.sweep_for_events(key_only=True)
state.sweep_for_crystal_access()
sphere = list(filter(lambda loc: state.can_reach(loc) and state.not_flooding_a_key(world, loc), required_locations))
+3 -3
View File
@@ -481,7 +481,7 @@ def create_regions(world, player):
create_dungeon_region(player, 'Ice Cross Left', 'Ice Palace', None, ['Ice Cross Left WS', 'Ice Cross Left Push Block']),
create_dungeon_region(player, 'Ice Cross Bottom', 'Ice Palace', None, ['Ice Cross Bottom SE', 'Ice Cross Bottom Push Block Left', 'Ice Cross Bottom Push Block Right']),
create_dungeon_region(player, 'Ice Cross Right', 'Ice Palace', None, ['Ice Cross Right ES', 'Ice Cross Right Push Block Top', 'Ice Cross Right Push Block Bottom']),
create_dungeon_region(player, 'Ice Cross Top', 'Ice Palace', None, ['Ice Cross Top NE', 'Ice Cross Top Push Block Left', 'Ice Cross Top Push Block Right']),
create_dungeon_region(player, 'Ice Cross Top', 'Ice Palace', None, ['Ice Cross Top NE', 'Ice Cross Top Push Block Bottom', 'Ice Cross Top Push Block Right']),
create_dungeon_region(player, 'Ice Compass Room', 'Ice Palace', ['Ice Palace - Compass Chest'], ['Ice Compass Room NE']),
create_dungeon_region(player, 'Ice Pengator Switch', 'Ice Palace', None, ['Ice Pengator Switch WS', 'Ice Pengator Switch ES']),
create_dungeon_region(player, 'Ice Dead End', 'Ice Palace', None, ['Ice Dead End WS']),
@@ -560,8 +560,8 @@ def create_regions(world, player):
create_dungeon_region(player, 'Mire Conveyor Barrier', 'Misery Mire', None, ['Mire Conveyor Barrier NW', 'Mire Conveyor Barrier Up Stairs']),
create_dungeon_region(player, 'Mire BK Chest Ledge', 'Misery Mire', ['Misery Mire - Big Key Chest'], ['Mire BK Chest Ledge WS']),
create_dungeon_region(player, 'Mire Warping Pool', 'Misery Mire', None, ['Mire Warping Pool ES', 'Mire Warping Pool Warp']),
create_dungeon_region(player, 'Mire Torches Top', 'Misery Mire', None, ['Mire Torches Top Down Stairs', 'Mire Torches Top SW']),
create_dungeon_region(player, 'Mire Torches Bottom', 'Misery Mire', None, ['Mire Torches Bottom NW', 'Mire Torches Bottom WS']),
create_dungeon_region(player, 'Mire Torches Top', 'Misery Mire', None, ['Mire Torches Top Down Stairs', 'Mire Torches Top SW', 'Mire Torches Top Holes']),
create_dungeon_region(player, 'Mire Torches Bottom', 'Misery Mire', None, ['Mire Torches Bottom NW', 'Mire Torches Bottom WS', 'Mire Torches Bottom Holes']),
create_dungeon_region(player, 'Mire Attic Hint', 'Misery Mire', None, ['Mire Attic Hint ES', 'Mire Attic Hint Hole']),
create_dungeon_region(player, 'Mire Dark Shooters', 'Misery Mire', None, ['Mire Dark Shooters Up Stairs', 'Mire Dark Shooters SW', 'Mire Dark Shooters SE']),
create_dungeon_region(player, 'Mire Key Rupees', 'Misery Mire', None, ['Mire Key Rupees NE']),
+5 -2
View File
@@ -1254,8 +1254,11 @@ def patch_rom(world, player, rom, enemized):
# set rom name
# 21 bytes
from Main import __version__
rom.name = bytearray('ER{0}_{1}_{2:09}\0'.format(__version__.split('-')[0].replace('.','')[0:3], player, world.seed), 'utf8')
rom.write_bytes(0x7FC0, rom.name[0:21])
# todo: change to DR when Enemizer is okay with DR
rom.name = bytearray('ER_{0}_{1:09}\0'.format(__version__[0:7], world.seed), 'utf8')
assert len(rom.name) <= 21
rom.write_bytes(0x7FC0, rom.name)
rom.name[0] = ord('D')
# Write title screen Code
hashint = int(rom.get_hash(), 16)
+1
View File
@@ -233,6 +233,7 @@ def create_rooms(world, player):
# Room(player, 0xff, 0x52c9a).door(Position.InteriorW, DoorKind.Bombable).door(Position.InteriorE, DoorKind.Bombable).door(Position.SouthE, DoorKind.CaveEntrance),
]
# fix some wonky things
world.get_room(0x51, player).change(1, DoorKind.Normal) # fix the dungeon changer
world.get_room(0x60, player).swap(2, 4) # puts the exit at pos 2 - enables pos 3
world.get_room(0x61, player).swap(1, 6) # puts the WN door at pos 1 - enables it
world.get_room(0x61, player).swap(5, 6) # puts the Incognito Entrance at the end, so it can be deleted
+49
View File
@@ -311,6 +311,55 @@ def global_rules(world, player):
set_defeat_dungeon_boss_rule(world.get_location('Agahnim 2', player))
add_key_logic_rules(world, player)
# crystal switch rules
set_rule(world.get_entrance('PoD Arena Crystal Path', player), lambda state: state.can_reach_blue(world.get_region('PoD Arena Crystal', player), player))
set_rule(world.get_entrance('Swamp Trench 2 Pots Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Swamp Trench 2 Pots', player), player))
set_rule(world.get_entrance('Swamp Shortcut Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Swamp Shortcut', player), player))
set_rule(world.get_entrance('Thieves Attic ES', player), lambda state: state.can_reach_blue(world.get_region('Thieves Attic', player), player))
set_rule(world.get_entrance('Thieves Hellway Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Thieves Hellway', player), player))
set_rule(world.get_entrance('Thieves Hellway Crystal Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Thieves Hellway N Crystal', player), player))
set_rule(world.get_entrance('Thieves Triple Bypass SE', player), lambda state: state.can_reach_blue(world.get_region('Thieves Triple Bypass', player), player))
set_rule(world.get_entrance('Thieves Triple Bypass WN', player), lambda state: state.can_reach_blue(world.get_region('Thieves Triple Bypass', player), player))
set_rule(world.get_entrance('Thieves Triple Bypass EN', player), lambda state: state.can_reach_blue(world.get_region('Thieves Triple Bypass', player), player))
set_rule(world.get_entrance('Ice Crystal Right Blue Hole', player), lambda state: state.can_reach_blue(world.get_region('Ice Crystal Right', player), player))
set_rule(world.get_entrance('Ice Crystal Left Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Ice Crystal Left', player), player))
set_rule(world.get_entrance('Ice Backwards Room Hole', player), lambda state: state.can_reach_blue(world.get_region('Ice Backwards Room', player), player))
set_rule(world.get_entrance('Mire Hub Upper Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Hub', player), player))
set_rule(world.get_entrance('Mire Hub Lower Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Hub', player), player))
set_rule(world.get_entrance('Mire Hub Right Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Hub Right', player), player))
set_rule(world.get_entrance('Mire Hub Top Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Hub Top', player), player))
set_rule(world.get_entrance('Mire Map Spike Side Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Map Spike Side', player), player))
set_rule(world.get_entrance('Mire Map Spot Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Map Spot', player), player))
set_rule(world.get_entrance('Mire Crystal Dead End Left Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Crystal Dead End', player), player))
set_rule(world.get_entrance('Mire Crystal Dead End Right Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Crystal Dead End', player), player))
set_rule(world.get_entrance('Mire South Fish Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire South Fish', player), player))
set_rule(world.get_entrance('Mire Compass Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Compass Room', player), player))
set_rule(world.get_entrance('Mire Crystal Mid Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Crystal Mid', player), player))
set_rule(world.get_entrance('Mire Crystal Left Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('Mire Crystal Left', player), player))
set_rule(world.get_entrance('TR Crystal Maze Blue Path', player), lambda state: state.can_reach_blue(world.get_region('TR Crystal Maze End', player), player))
set_rule(world.get_entrance('GT Hookshot Entry Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('GT Hookshot South Entry', player), player))
set_rule(world.get_entrance('GT Double Switch Key Blue Path', player), lambda state: state.can_reach_blue(world.get_region('GT Double Switch Key Spot', player), player))
set_rule(world.get_entrance('GT Double Switch Blue Barrier', player), lambda state: state.can_reach_blue(world.get_region('GT Double Switch Switches', player), player))
set_rule(world.get_entrance('GT Double Switch Transition Blue', player), lambda state: state.can_reach_blue(world.get_region('GT Double Switch Transition', player), player))
set_rule(world.get_entrance('Swamp Barrier Ledge - Orange', player), lambda state: state.can_reach_orange(world.get_region('Swamp Barrier Ledge', player), player))
set_rule(world.get_entrance('Swamp Barrier - Orange', player), lambda state: state.can_reach_orange(world.get_region('Swamp Barrier', player), player))
set_rule(world.get_entrance('Thieves Hellway Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Thieves Hellway', player), player))
set_rule(world.get_entrance('Thieves Hellway Crystal Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Thieves Hellway S Crystal', player), player))
set_rule(world.get_entrance('Ice Bomb Jump Ledge Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Ice Bomb Jump Ledge', player), player))
set_rule(world.get_entrance('Ice Bomb Jump Catwalk Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Ice Bomb Jump Catwalk', player), player))
set_rule(world.get_entrance('Ice Crystal Right Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Ice Crystal Right', player), player))
set_rule(world.get_entrance('Ice Crystal Left Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Ice Crystal Left', player), player))
set_rule(world.get_entrance('Mire Crystal Right Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Mire Crystal Right', player), player))
set_rule(world.get_entrance('Mire Crystal Mid Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Mire Crystal Mid', player), player))
set_rule(world.get_entrance('Mire Firesnake Skip Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Mire Firesnake Skip', player), player))
set_rule(world.get_entrance('Mire Antechamber Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('Mire Antechamber', player), player))
set_rule(world.get_entrance('GT Double Switch Orange Barrier', player), lambda state: state.can_reach_orange(world.get_region('GT Double Switch Entry', player), player))
set_rule(world.get_entrance('GT Double Switch Orange Barrier 2', player), lambda state: state.can_reach_orange(world.get_region('GT Double Switch Entry', player), player))
set_rule(world.get_entrance('GT Double Switch Orange Path', player), lambda state: state.can_reach_orange(world.get_region('GT Double Switch Switches', player), player))
set_rule(world.get_entrance('GT Double Switch Key Orange Path', player), lambda state: state.can_reach_orange(world.get_region('GT Double Switch Key Spot', player), player))
# End of door rando rules.
add_rule(world.get_location('Sunken Treasure', player), lambda state: state.has('Open Floodgate', player))
+39
View File
@@ -188,5 +188,44 @@ def read_entrance_data(old_rom='Zelda no Densetsu - Kamigami no Triforce (Japan)
print("%s: %s" % (dp, bytes))
def print_wiki_doors(d_regions, world, player):
for d, region_list in d_regions.items():
tile_map = {}
for region in region_list:
tile = None
r = world.get_region(region, player)
for ext in r.exits:
door = world.check_for_door(ext.name, player)
if door is not None and door.roomIndex != -1:
tile = door.roomIndex
break
if tile is not None:
if tile not in tile_map:
tile_map[tile] = []
tile_map[tile].append(r)
print(d)
print('{| class="wikitable"')
print('|-')
print('! Room')
print('! Supertile')
print('! Doors')
for tile, region_list in tile_map.items():
tile_done = False
for region in region_list:
print('|-')
print('| '+region.name)
if not tile_done:
listlen = len(region_list)
link = '| {{UnderworldMapLink|'+str(tile)+'}}'
print(link if listlen < 2 else '| rowspan = '+str(listlen)+' '+link)
tile_done = True
strs_to_print = []
for ext in region.exits:
strs_to_print.append(ext.name)
print('| '+' <br /> '.join(strs_to_print))
print('|}')
if __name__ == '__main__':
read_entrance_data(old_rom='C:\\Users\\Randall\\Documents\\kwyn\\orig\\z3.sfc')
+2 -2
View File
@@ -43,8 +43,8 @@ org $00d6ae ;(PC: 56ae)
LoadTransAuxGfx:
org $00df5a ;(PC: 5f5a)
PrepTransAuxGfx:
;org $0ffd65 ;(PC: 07fd65)
;Dungeon_LoadCustomTileAttr:
org $0ffd65 ;(PC: 07fd65)
Dungeon_LoadCustomTileAttr:
;org $01fec1
;Dungeon_ApproachFixedColor_variable:
;org $a0f972 ; Rando version
+1 -1
View File
@@ -4,7 +4,7 @@ GfxFixer:
jsl LoadRoomHook ; this is the rando version - let's only call this guy once - may fix star tiles and slower loads
jsl Dungeon_InitStarTileCh
jsl LoadTransAuxGfx
;jsl Dungeon_LoadCustomTileAttr
jsl Dungeon_LoadCustomTileAttr
jsl PrepTransAuxGfx
lda #$09 : sta $17 : sta $0710
jsl Palette_SpriteAux3
File diff suppressed because one or more lines are too long