Finish bps work
Fixing a couple bugs
This commit is contained in:
@@ -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
3
CLI.py
@@ -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": "",
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
4
Main.py
4
Main.py
@@ -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':
|
||||
|
||||
28
README.md
28
README.md
@@ -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)
|
||||
|
||||
|
||||
@@ -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
8
Rom.py
@@ -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:
|
||||
|
||||
7
Utils.py
7
Utils.py
@@ -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.
@@ -63,6 +63,13 @@
|
||||
"action": "store_true",
|
||||
"type": "bool"
|
||||
},
|
||||
"mixed_travel" : {
|
||||
"choices": [
|
||||
"prevent",
|
||||
"allow",
|
||||
"force"
|
||||
]
|
||||
},
|
||||
"timer": {
|
||||
"choices": [
|
||||
"none",
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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",
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user