Finish bps work

Fixing a couple bugs
This commit is contained in:
aerinon
2020-10-29 15:46:27 -06:00
parent a02dcd0ba4
commit d3e643b9c6
14 changed files with 139 additions and 31 deletions

View File

@@ -128,6 +128,7 @@ class World(object):
set_player_attr('treasure_hunt_count', 0)
set_player_attr('keydropshuffle', False)
set_player_attr('mixed_travel', 'prevent')
def get_name_string_for_object(self, obj):
return obj.name if self.players == 1 else f'{obj.name} ({self.get_player_names(obj.player)})'

3
CLI.py
View File

@@ -95,7 +95,7 @@ def parse_cli(argv, no_defaults=False):
'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots',
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'heartbeep',
'remote_items', 'keydropshuffle']:
'remote_items', 'keydropshuffle', 'mixed_travel']:
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)
if player == 1:
setattr(ret, name, {1: value})
@@ -145,6 +145,7 @@ def parse_settings():
"intensity": 2,
"experimental": False,
"dungeon_counters": "default",
"mixed_travel": "prevent",
"multi": 1,
"names": "",

View File

@@ -154,20 +154,39 @@ def vanilla_key_logic(world, player):
world.dungeon_layouts[player][builder.name] = builder
add_inaccessible_doors(world, player)
for builder in builders:
origin_list = find_accessible_entrances(world, player, default_dungeon_entrances[builder.name])
start_regions = convert_regions(origin_list, world, player)
doors = convert_key_doors(default_small_key_doors[builder.name], world, player)
key_layout = build_key_layout(builder, start_regions, doors, world, player)
valid = validate_key_layout(key_layout, world, player)
if not valid:
logging.getLogger('').warning('Vanilla key layout not valid %s', builder.name)
builder.key_door_proposal = doors
if player not in world.key_logic.keys():
world.key_logic[player] = {}
analyze_dungeon(key_layout, world, player)
world.key_logic[player][builder.name] = key_layout.key_logic
log_key_logic(builder.name, key_layout.key_logic)
entrances_map, potentials, connections = determine_entrance_list(world, player)
enabled_entrances = {}
sector_queue = deque(builders)
last_key, loops = None, 0
while len(sector_queue) > 0:
builder = sector_queue.popleft()
split_dungeon = builder.name.startswith('Desert Palace') or builder.name.startswith('Skull Woods')
origin_list = list(entrances_map[builder.name])
find_enabled_origins(builder.sectors, enabled_entrances, origin_list, entrances_map, builder.name)
if len(origin_list) <= 0 or not pre_validate(builder, origin_list, split_dungeon, world, player):
if last_key == builder.name or loops > 1000:
origin_name = world.get_region(origin_list[0], player).entrances[0].parent_region.name if len(origin_list) > 0 else 'no origin'
raise Exception('Infinite loop detected for "%s" located at %s' % (builder.name, origin_name))
sector_queue.append(builder)
last_key = builder.name
loops += 1
else:
find_new_entrances(builder.master_sector, entrances_map, connections, potentials, enabled_entrances, world, player)
start_regions = convert_regions(origin_list, world, player)
doors = convert_key_doors(default_small_key_doors[builder.name], world, player)
key_layout = build_key_layout(builder, start_regions, doors, world, player)
valid = validate_key_layout(key_layout, world, player)
if not valid:
logging.getLogger('').warning('Vanilla key layout not valid %s', builder.name)
builder.key_door_proposal = doors
if player not in world.key_logic.keys():
world.key_logic[player] = {}
analyze_dungeon(key_layout, world, player)
world.key_logic[player][builder.name] = key_layout.key_logic
log_key_logic(builder.name, key_layout.key_logic)
last_key = None
if world.shuffle[player] == 'vanilla' and world.accessibility[player] == 'items' and not world.retro[player] and not world.keydropshuffle[player]:
validate_vanilla_key_logic(world, player)
@@ -837,6 +856,7 @@ def cross_dungeon(world, player):
for key in dungeon_regions.keys():
all_regions += dungeon_regions[key]
all_sectors.extend(convert_to_sectors(all_regions, world, player))
merge_sectors(all_sectors, world, player)
entrances, splits = create_dungeon_entrances(world, player)
dungeon_builders = create_dungeon_builders(all_sectors, connections_tuple, world, player, entrances, splits)
for builder in dungeon_builders.values():
@@ -1076,6 +1096,30 @@ def convert_to_sectors(region_names, world, player):
return sectors
def merge_sectors(all_sectors, world, player):
if world.mixed_travel[player] == 'force':
sectors_to_remove = {}
merge_sectors = {}
for sector in all_sectors:
r_set = sector.region_set()
if 'PoD Arena Ledge' in r_set:
sectors_to_remove['Arenahover'] = sector
elif 'PoD Big Chest Balcony' in r_set:
sectors_to_remove['Hammerjump'] = sector
elif 'Mire Chest View' in r_set:
sectors_to_remove['Mire BJ'] = sector
elif 'PoD Falling Bridge Ledge' in r_set:
merge_sectors['Hammerjump'] = sector
elif 'PoD Arena Bridge' in r_set:
merge_sectors['Arenahover'] = sector
elif 'Mire BK Chest Ledge' in r_set:
merge_sectors['Mire BJ'] = sector
for key, old_sector in sectors_to_remove.items():
merge_sectors[key].regions.extend(old_sector.regions)
merge_sectors[key].outstanding_doors.extend(old_sector.outstanding_doors)
all_sectors.remove(old_sector)
# those with split region starts like Desert/Skull combine for key layouts
def combine_layouts(recombinant_builders, dungeon_builders, entrances_map):
for recombine in recombinant_builders.values():
@@ -1697,6 +1741,7 @@ class DROptions(Flag):
Town_Portal = 0x02 # If on, Players will start with mirror scroll
Map_Info = 0x04
Debug = 0x08
Rails = 0x10 # If on, draws rails
Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required

View File

@@ -24,7 +24,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
from ItemList import generate_itempool, difficulties, fill_prizes
from Utils import output_path, parse_player_names
__version__ = '0.2.0.4-u'
__version__ = '0.2.0.5-u'
class EnemizerError(RuntimeError):
pass
@@ -67,6 +67,7 @@ def main(args, seed=None, fish=None):
world.dungeon_counters = args.dungeon_counters.copy()
world.fish = fish
world.keydropshuffle = args.keydropshuffle.copy()
world.mixed_travel = args.mixed_travel.copy()
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)}
@@ -374,6 +375,7 @@ def copy_world(world):
ret.intensity = world.intensity.copy()
ret.experimental = world.experimental.copy()
ret.keydropshuffle = world.keydropshuffle.copy()
ret.mixed_travel = world.mixed_travel.copy()
for player in range(1, world.players + 1):
if world.mode[player] != 'inverted':

View File

@@ -22,7 +22,7 @@ Alternatively, run ```Gui.py``` for a simple graphical user interface. (WIP)
Only extra settings are found here. All entrance randomizer settings are supported. See their [readme](https://github.com/KevinCathcart/ALttPEntranceRandomizer/blob/master/README.md)
## Door Shuffle
## Door Shuffle (--doorShuffle)
### Basic
@@ -36,7 +36,7 @@ Doors are shuffled between dungeons as well.
Doors are not shuffled.
## Intensity
## Intensity (--intensity number)
#### Level 1
Normal door and spiral staircases are shuffled
@@ -45,14 +45,32 @@ Same as Level 1 plus open edges and straight staircases are shuffled.
#### Level 3
Same as Level 2 plus Dungeon Lobbies are shuffled
## KeyDropShuffle
--keydropshuffle in CLI
## KeyDropShuffle (--keydropshuffle)
Adds 33 new locations to the randomization pool. The 32 small keys found under pots and dropped by enemies and the Big
Key drop location are added to the pool. The keys normally found there are added to the item pool. Retro adds
32 generic keys to the pool instead.
## Crossed Dungeon Specific Settings
### Mixed Travel (--mixed_travel value)
Due to Hammerjump, Hovering in PoD Arena, and the Mire Big Key Chest bomb jump two sections of a supertile that are
otherwise unconnected logically can be reach using these glitches. To prevent the player from unintentionally
#### Prevent
Rails are added the 3 spots to prevent this tricks. This setting is recommend for those learning crossed dungeon mode to
learn what is dangerous and what is not. No logic seeds ignore this setting.
#### Allow
The rooms are left alone and it is up to the discretion of the player whether to use these tricks or not.
#### Force
The two disjointed sections are forced to be in the same dungeon but never logically required to complete that game.
## Map/Compass/Small Key/Big Key shuffle (aka Keysanity)

View File

@@ -12,6 +12,13 @@ and where enemies drop keys. This includes 32 small key location and the ball an
Big Key.
* Multiworld untested - May need changes to MultiClient/MultiServer to recognize new locations
* GT Big Key count / total location count needs to be updated
* --mixed_travel setting added
* Due to Hammerjump, Hovering in PoD Arena, and the Mire Big Key Chest bomb jump two sections of a supertile that are
otherwise unconnected logically can be reach using these glitches. To prevent the player from unintentionally
* prevent: Rails are added the 3 spots to prevent this tricks. This setting is recommend for those learning
crossed dungeon mode to learn what is dangerous and what is not. No logic seeds ignore this setting.
* allow: The rooms are left alone and it is up to the discretion of the player whether to use these tricks or not.
* force: The two disjointed sections are forced to be in the same dungeon but never logically required to complete that game.
### Experimental features
@@ -27,11 +34,10 @@ Big Key.
* Fixed a problem ER shuffle generation that did not account for lobbies moving around
* Fixed a problem with camera unlock (GT Mimics and Mire Minibridge)
* Fixed a problem with bad-pseudo layer at PoD map Balcony (unable to hit switch with Bomb)
* Fixed a problem with the Ganon hint when hints are turned off
# Known Issues
(I'm planning to fix theese in this Unstable iteration hopefully)
* Hammerjump (et al) rails
* Backward TR Crystal Maze locking Somaria
* Ganon hint when hints are turned off not correct

8
Rom.py
View File

@@ -24,7 +24,7 @@ from EntranceShuffle import door_addresses, exit_ids
JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = 'c83a85f4dca8a0f264280aecde8e41c2'
RANDOMIZERBASEHASH = '6904a4588b21d1674e1fa25e96da8339'
class JsonRom(object):
@@ -624,6 +624,10 @@ def patch_rom(world, rom, player, team, enemized):
if world.experimental[player]:
dr_flags |= DROptions.Map_Info
dr_flags |= DROptions.Debug
if world.doorShuffle[player] == 'crossed' and world.logic[player] != 'nologic'\
and world.mixed_travel[player] == 'prevent':
dr_flags |= DROptions.Rails
# fix hc big key problems
if world.doorShuffle[player] == 'crossed' or world.keydropshuffle[player]:
@@ -1358,7 +1362,7 @@ def patch_rom(world, rom, player, team, enemized):
item_dungeon = hera_basement.item.name.split('(')[1][:-1]
if item_dungeon == 'Escape':
item_dungeon = 'Hyrule Castle'
is_small_key_this_dungeon = hera_basement.dungeon.name == item_dungeon
is_small_key_this_dungeon = hera_basement.parent_region.dungeon.name == item_dungeon
if is_small_key_this_dungeon:
rom.write_byte(0x4E3BB, 0xE4)
else:

View File

@@ -575,7 +575,8 @@ def extract_data_from_jp_rom(rom):
with open(rom, 'rb') as stream:
rom_data = bytearray(stream.read())
rooms = [0x7b, 0x7c, 0x7d, 0x8b, 0x8c, 0x8d, 0x9b, 0x9c, 0x9d]
# rooms = [0x7b, 0x7c, 0x7d, 0x8b, 0x8c, 0x8d, 0x9b, 0x9c, 0x9d]
rooms = [0x1a, 0x2a, 0xd1]
for room in rooms:
b2idx = room*2
b3idx = room*3
@@ -652,6 +653,6 @@ if __name__ == '__main__':
# make_new_base2current()
# read_entrance_data(old_rom=sys.argv[1])
# room_palette_data(old_rom=sys.argv[1])
extract_data_from_us_rom(sys.argv[1])
# extract_data_from_jp_rom(sys.argv[1])
# extract_data_from_us_rom(sys.argv[1])
extract_data_from_jp_rom(sys.argv[1])

Binary file not shown.

View File

@@ -63,6 +63,13 @@
"action": "store_true",
"type": "bool"
},
"mixed_travel" : {
"choices": [
"prevent",
"allow",
"force"
]
},
"timer": {
"choices": [
"none",

View File

@@ -245,6 +245,12 @@
"keyshuffle": [ "Small Keys are no longer restricted to their dungeons, but can be anywhere. (default: %(default)s)" ],
"bigkeyshuffle": [ "Big Keys are no longer restricted to their dungeons, but can be anywhere. (default: %(default)s)" ],
"keydropshuffle": [ "Key Drops (Pots and Enemies) are shuffled and other items can take their place (default: %(default)s)" ],
"mixed_travel": [
"How to handle potential traversal between dungeon in Crossed door shuffle",
"Prevent: Rails are placed to prevent bombs jump and hovering from changing dungeon except with glitched logic settings",
"Allow: Take the rails off, \"I know what I'm doing\"",
"Force: Force these troublesome connections to be in the same dungeon (but not in logic). No rails will appear"
],
"retro": [
"Keys are universal, shooting arrows costs rupees,",
"and a few other little things make this more like Zelda-1. (default: %(default)s)"

View File

@@ -72,6 +72,10 @@
"randomizer.dungeon.dungeon_counters.on": "On",
"randomizer.dungeon.dungeon_counters.pickup": "On Compass Pickup",
"randomizer.dungeon.mixed_travel": "Mixed Dungeon Travel ",
"randomizer.dungeon.mixed_travel.prevent": "Prevent Mixed Dungeon Travel",
"randomizer.dungeon.mixed_travel.allow": "Allow Mixed Dungeon Travel",
"randomizer.dungeon.mixed_travel.force": "Force Reachable Areas to Same Dungeon",
"randomizer.enemizer.potshuffle": "Pot Shuffle",

View File

@@ -19,7 +19,7 @@
"random"
],
"config": {
"width": 40
"width": 35
}
},
"experimental": { "type": "checkbox" },
@@ -32,6 +32,18 @@
"on",
"pickup"
]
},
"mixed_travel": {
"type" : "selectbox",
"default": "auto",
"options": [
"prevent",
"allow",
"force"
],
"config": {
"width": 35
}
}
}
}

View File

@@ -90,7 +90,8 @@ SETTINGSTOPROCESS = {
"dungeondoorshuffle": "door_shuffle",
"dungeonintensity": "intensity",
"experimental": "experimental",
"dungeon_counters": "dungeon_counters"
"dungeon_counters": "dungeon_counters",
"mixed_travel": "mixed_travel"
},
"gameoptions": {
"hints": "hints",