Start of attempt for vanilla item placements

This commit is contained in:
2026-05-14 00:14:54 -05:00
parent cdfdc15219
commit 924bd7a616
6 changed files with 269 additions and 10 deletions

View File

@@ -2895,6 +2895,10 @@ class Item(object):
def compass(self): def compass(self):
return self.type == 'Compass' return self.type == 'Compass'
@property
def event(self):
return self.type == 'Event'
@property @property
def dungeon(self): def dungeon(self):
if not self.smallkey and not self.bigkey and not self.map and not self.compass: if not self.smallkey and not self.bigkey and not self.map and not self.compass:

1
CLI.py
View File

@@ -89,6 +89,7 @@ def parse_cli(argv, no_defaults=False):
parser.add_argument('--count', default=defval(int(settings["count"]) if settings["count"] != "" and settings["count"] is not None else 1), help="\n".join(fish.translate("cli", "help", "count")), type=int) parser.add_argument('--count', default=defval(int(settings["count"]) if settings["count"] != "" and settings["count"] is not None else 1), help="\n".join(fish.translate("cli", "help", "count")), type=int)
parser.add_argument('--tries', default=defval(int(settings["tries"]) if settings["tries"] != "" and settings["tries"] is not None else 1), help="\n".join(fish.translate("cli", "help", "tries")), type=int) parser.add_argument('--tries', default=defval(int(settings["tries"]) if settings["tries"] != "" and settings["tries"] is not None else 1), help="\n".join(fish.translate("cli", "help", "tries")), type=int)
parser.add_argument('--customitemarray', default={}, help=argparse.SUPPRESS) parser.add_argument('--customitemarray', default={}, help=argparse.SUPPRESS)
parser.add_argument('--skip_money_balance', action="store_true", help=argparse.SUPPRESS)
# included for backwards compatibility # included for backwards compatibility
parser.add_argument('--multi', default=defval(settings["multi"]), type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--multi', default=defval(settings["multi"]), type=lambda value: min(max(int(value), 1), 255))

View File

@@ -252,6 +252,7 @@ def verify_spot_to_fill(location, item_to_place, max_exp_state, single_player_pl
or (world.algorithm == 'vanilla_fill' and item_to_place.is_near_dungeon_item(world)))) \ or (world.algorithm == 'vanilla_fill' and item_to_place.is_near_dungeon_item(world)))) \
or valid_dungeon_placement(item_to_place, location, world): or valid_dungeon_placement(item_to_place, location, world):
return location return location
if item_to_place.smallkey or item_to_place.bigkey or item_to_place.prize: if item_to_place.smallkey or item_to_place.bigkey or item_to_place.prize:
location.item = None location.item = None
location.event = False location.event = False
@@ -311,7 +312,9 @@ def valid_dungeon_placement(item, location, world):
dungeon = check_dungeon dungeon = check_dungeon
if dungeon: if dungeon:
layout = world.dungeon_layouts[location.player][dungeon.name] layout = world.dungeon_layouts[location.player][dungeon.name]
if not is_dungeon_item(item, world) or item.player != location.player: if item.event:
return True
elif not is_dungeon_item(item, world) or item.player != location.player:
if item.prize and item.is_near_dungeon_item(world): if item.prize and item.is_near_dungeon_item(world):
return item.dungeon_object == dungeon and layout.free_items > 0 return item.dungeon_object == dungeon and layout.free_items > 0
return layout.free_items > 0 return layout.free_items > 0

View File

@@ -372,6 +372,13 @@ def generate_itempool(world, player):
world.push_precollected(ItemFactory(item, player)) world.push_precollected(ItemFactory(item, player))
if world.mode[player] == 'standard' and not world.state.has_blunt_weapon(player): if world.mode[player] == 'standard' and not world.state.has_blunt_weapon(player):
if world.customizer:
placements = world.customizer.get_placements()
if placements:
custom_uncle = placements.get(player, {}).get("Link's Uncle")
if custom_uncle:
placed_items["Link's Uncle"] = custom_uncle
if "Link's Uncle" not in placed_items: if "Link's Uncle" not in placed_items:
found_sword = False found_sword = False
found_bow = False found_bow = False
@@ -1669,12 +1676,15 @@ def fill_specific_items(world):
item_to_place, event_flag = get_item_and_event_flag(item, world, player, item_to_place, event_flag = get_item_and_event_flag(item, world, player,
dungeon_pool, prize_set, prize_pool) dungeon_pool, prize_set, prize_pool)
if item_to_place: if item_to_place:
world.push_item(loc, item_to_place, False) if not loc.item:
loc.locked = True world.push_item(loc, item_to_place, False)
track_outside_keys(item_to_place, loc, world) loc.locked = True
track_dungeon_items(item_to_place, loc, world) track_outside_keys(item_to_place, loc, world)
loc.event = (event_flag or item_to_place.advancement track_dungeon_items(item_to_place, loc, world)
or item_to_place.bigkey or item_to_place.smallkey) loc.event = (event_flag or item_to_place.advancement
or item_to_place.bigkey or item_to_place.smallkey)
elif loc.item != item_to_place:
logging.getLogger('').warning("Failed to place item %s at location %s because it already contained %s", item_to_place, loc.name, loc.item)
else: else:
raise Exception(f'Did not find "{item}" in item pool to place at "{location}"') raise Exception(f'Did not find "{item}" in item pool to place at "{location}"')
advanced_placements = world.customizer.get_advanced_placements() advanced_placements = world.customizer.get_advanced_placements()
@@ -1802,7 +1812,7 @@ def shuffle_event_items(world, player):
continue continue
break break
else: else:
raise FillError(f'Unable to place followers: {", ".join(list(map(lambda d: d.hint_text, follower_locations)))}') raise FillError(f'Unable to place followers: {", ".join(list(map(lambda f: f.name, pickup_items)))}')
def get_item_and_event_flag(item, world, player, dungeon_pool, prize_set, prize_pool): def get_item_and_event_flag(item, world, player, dungeon_pool, prize_set, prize_pool):

View File

@@ -335,7 +335,7 @@ def main(args, seed=None, fish=None):
for player in range(1, world.players+1): for player in range(1, world.players+1):
if world.shopsanity[player]: if world.shopsanity[player]:
customize_shops(world, player) customize_shops(world, player)
if args.algorithm in ['balanced', 'equitable']: if not args.skip_money_balance and args.algorithm in ['balanced', 'equitable']:
balance_money_progression(world) balance_money_progression(world)
ensure_good_items(world, True) ensure_good_items(world, True)
@@ -572,7 +572,7 @@ def init_world(args, fish):
world.collection_rate = args.collection_rate.copy() world.collection_rate = args.collection_rate.copy()
world.colorizepots = args.colorizepots.copy() world.colorizepots = args.colorizepots.copy()
world.aga_randomness = args.aga_randomness.copy() world.aga_randomness = args.aga_randomness.copy()
world.money_balance = args.money_balance.copy() world.money_balance = {player: int(args.money_balance[player]) for player in range(1, world.players + 1)}
# custom settings - these haven't been promoted to full settings yet # custom settings - these haven't been promoted to full settings yet
in_progress_settings = ['force_enemy'] in_progress_settings = ['force_enemy']
@@ -1288,6 +1288,8 @@ def create_playthrough(world):
for location in sphere: for location in sphere:
if world.goal[location.player] == 'completionist': if world.goal[location.player] == 'completionist':
continue # every location for that player is required continue # every location for that player is required
if location.item.type == "SmallKey":
continue
# we remove the item at location and check if game is still beatable # we remove the item at location and check if game is still beatable
logging.getLogger('').debug('Checking if %s (Player %d) is required to beat the game.', location.item.name, location.item.player) logging.getLogger('').debug('Checking if %s (Player %d) is required to beat the game.', location.item.name, location.item.player)
old_item = location.item old_item = location.item

239
vanilla_placements.yaml Normal file
View File

@@ -0,0 +1,239 @@
item_pool_adjust:
1:
"Bottle (Random)": -4
"Bottle": 4
"Lamp": 1
"Bombs (10)": -1
"Bombs (3)": 1
placements:
1:
"Master Sword Pedestal": Master Sword
"Mushroom": Mushroom
"Ether Tablet": Ether
"Spectacle Rock": Piece of Heart
"Old Man": Magic Mirror
"Floating Island": Piece of Heart
"King Zora": Flippers
"Zora's Ledge": Piece of Heart
"Bottle Merchant": Bottle
"Maze Race": Piece of Heart
"Flute Spot": Ocarina
"Hobo": Bottle
"Desert Ledge": Piece of Heart
"Bombos Tablet": Bombos
"Lake Hylia Island": Piece of Heart
"Purple Chest": Bottle
"Sunken Treasure": Piece of Heart
"Bumper Cave Ledge": Piece of Heart
"Catfish": Quake
"Pyramid": Piece of Heart
"Digging Game": Piece of Heart
"Stumpy": Shovel
"Lost Woods Hideout": Piece of Heart
"Lumberjack Tree": Piece of Heart
"Spectacle Rock Cave": Piece of Heart
"Spiral Cave": Rupees (20)
"Mimic Cave": Piece of Heart
"Paradox Cave Lower - Far Left": Rupees (20)
"Paradox Cave Lower - Left": Rupees (20)
"Paradox Cave Lower - Right": Rupees (20)
"Paradox Cave Lower - Far Right": Rupees (20)
"Paradox Cave Lower - Middle": Rupees (20)
"Paradox Cave Upper - Left": Bombs (3)
"Paradox Cave Upper - Right": Arrows (10)
"Waterfall Fairy - Left": Red Boomerang
"Waterfall Fairy - Right": Red Shield
"Bonk Rock Cave": Piece of Heart
"Graveyard Cave": Piece of Heart
"King's Tomb": Cape
"Potion Shop": Magic Powder
"Kakariko Well - Left": Rupees (20)
"Kakariko Well - Middle": Rupees (20)
"Kakariko Well - Right": Rupees (20)
"Kakariko Well - Bottom": Bombs (3)
"Kakariko Well - Top": Piece of Heart
"Blind's Hideout - Left": Rupees (20)
"Blind's Hideout - Right": Rupees (20)
"Blind's Hideout - Far Left": Rupees (20)
"Blind's Hideout - Far Right": Rupees (20)
"Blind's Hideout - Top": Piece of Heart
"Chicken House": Arrows (10)
"Sick Kid": Bug Catching Net
"Kakariko Tavern": Bottle
"Link's Uncle": Fighter Sword
"Secret Passage": Blue Shield
"Sahasrahla's Hut - Left": Rupees (50)
"Sahasrahla's Hut - Middle": Bombs (3)
"Sahasrahla's Hut - Right": Rupees (50)
"Sahasrahla": Pegasus Boots
"Blacksmith": Tempered Sword
"Magic Bat": Magic Upgrade (1/2)
"Library": Book of Mudora
"Link's House": Lamp
"Checkerboard Cave": Piece of Heart
"Aginah's Cave": Piece of Heart
"Cave 45": Piece of Heart
"Mini Moldorm Cave - Far Left": Bombs (3)
"Mini Moldorm Cave - Left": Rupees (20)
"Mini Moldorm Cave - Right": Rupees (20)
"Mini Moldorm Cave - Far Right": Arrows (10)
"Mini Moldorm Cave - Generous Guy": Rupees (300)
"Ice Rod Cave": Ice Rod
"Floodgate Chest": Bombs (3)
"Spike Cave": Cane of Byrna
"Hookshot Cave - Bottom Right": Rupees (50)
"Hookshot Cave - Top Right": Rupees (50)
"Hookshot Cave - Top Left": Rupees (50)
"Hookshot Cave - Bottom Left": Rupees (50)
"Superbunny Cave - Top": Bombs (3)
"Superbunny Cave - Bottom": Rupees (50)
"Chest Game": Piece of Heart
"C-Shaped House": Rupees (300)
"Brewery": Rupees (300)
"Pyramid Fairy - Left": Golden Sword
"Pyramid Fairy - Right": Silver Arrows
"Peg Cave": Piece of Heart
"Mire Shed - Left": Piece of Heart
"Mire Shed - Right": Arrows (10)
"Hype Cave - Top": Rupees (20)
"Hype Cave - Middle Right": Rupees (20)
"Hype Cave - Middle Left": Rupees (20)
"Hype Cave - Bottom": Rupees (20)
"Hype Cave - Generous Guy": Rupees (300)
"Hyrule Castle - Map Chest": Map (Escape)
"Hyrule Castle - Boomerang Chest": Blue Boomerang
"Hyrule Castle - Zelda's Chest": Lamp
"Sewers - Dark Cross": Small Key (Escape)
"Sewers - Secret Room - Left": Bombs (3)
"Sewers - Secret Room - Middle": Rupees (300)
"Sewers - Secret Room - Right": Arrows (10)
"Sanctuary": Sanctuary Heart Container
"Eastern Palace - Cannonball Chest": Rupees (100)
"Eastern Palace - Map Chest": Map (Eastern Palace)
"Eastern Palace - Compass Chest": Compass (Eastern Palace)
"Eastern Palace - Big Chest": Bow
"Eastern Palace - Big Key Chest": Big Key (Eastern Palace)
"Eastern Palace - Boss": Boss Heart Container
"Eastern Palace - Prize": Green Pendant
"Desert Palace - Compass Chest": Compass (Desert Palace)
"Desert Palace - Big Key Chest": Big Key (Desert Palace)
"Desert Palace - Map Chest": Map (Desert Palace)
"Desert Palace - Torch": Small Key (Desert Palace)
"Desert Palace - Big Chest": Power Glove
"Desert Palace - Boss": Boss Heart Container
"Desert Palace - Prize": Blue Pendant
"Tower of Hera - Map Chest": Map (Tower of Hera)
"Tower of Hera - Basement Cage": Small Key (Tower of Hera)
"Tower of Hera - Big Key Chest": Big Key (Tower of Hera)
"Tower of Hera - Compass Chest": Compass (Tower of Hera)
"Tower of Hera - Big Chest": Moon Pearl
"Tower of Hera - Boss": Boss Heart Container
"Tower of Hera - Prize": Red Pendant
"Castle Tower - Room 03": Small Key (Agahnims Tower)
"Castle Tower - Dark Maze": Small Key (Agahnims Tower)
"Palace of Darkness - Shooter Room": Small Key (Palace of Darkness)
"Palace of Darkness - The Arena - Bridge": Small Key (Palace of Darkness)
"Palace of Darkness - The Arena - Ledge": Small Key (Palace of Darkness)
"Palace of Darkness - Map Chest": Map (Palace of Darkness)
"Palace of Darkness - Stalfos Basement": Small Key (Palace of Darkness)
"Palace of Darkness - Big Key Chest": Big Key (Palace of Darkness)
"Palace of Darkness - Dark Maze - Top": Rupees (20)
"Palace of Darkness - Dark Maze - Bottom": Rupees (5)
"Palace of Darkness - Big Chest": Hammer
"Palace of Darkness - Compass Chest": Compass (Palace of Darkness)
"Palace of Darkness - Dark Basement - Left": Single Arrow
"Palace of Darkness - Dark Basement - Right": Small Key (Palace of Darkness)
"Palace of Darkness - Harmless Hellway": Small Key (Palace of Darkness)
"Palace of Darkness - Boss": Boss Heart Container
"Palace of Darkness - Prize": Crystal 3
"Thieves' Town - Map Chest": Map (Thieves Town)
"Thieves' Town - Ambush Chest": Rupees (20)
"Thieves' Town - Compass Chest": Compass (Thieves Town)
"Thieves' Town - Big Key Chest": Big Key (Thieves Town)
"Thieves' Town - Boss": Boss Heart Container
"Thieves' Town - Prize": Crystal 4
"Thieves' Town - Attic": Bombs (3)
"Thieves' Town - Blind's Cell": Small Key (Thieves Town)
"Thieves' Town - Big Chest": Titans Mitts
"Skull Woods - Map Chest": Map (Skull Woods)
"Skull Woods - Big Chest": Fire Rod
"Skull Woods - Pinball Room": Small Key (Skull Woods)
"Skull Woods - Pot Prison": Small Key (Skull Woods)
"Skull Woods - Compass Chest": Compass (Skull Woods)
"Skull Woods - Big Key Chest": Big Key (Skull Woods)
"Skull Woods - Bridge Room": Small Key (Skull Woods)
"Skull Woods - Boss": Boss Heart Container
"Skull Woods - Prize": Crystal 7
"Swamp Palace - Entrance": Small Key (Swamp Palace)
"Swamp Palace - Map Chest": Map (Swamp Palace)
"Swamp Palace - Big Chest": Hookshot
"Swamp Palace - Compass Chest": Compass (Swamp Palace)
"Swamp Palace - Big Key Chest": Big Key (Swamp Palace)
"Swamp Palace - West Chest": Rupees (20)
"Swamp Palace - Flooded Room - Left": Rupees (20)
"Swamp Palace - Flooded Room - Right": Rupees (20)
"Swamp Palace - Waterfall Room": Rupees (20)
"Swamp Palace - Boss": Boss Heart Container
"Swamp Palace - Prize": Crystal 1
"Ice Palace - Compass Chest": Compass (Ice Palace)
"Ice Palace - Big Key Chest": Big Key (Ice Palace)
"Ice Palace - Spike Room": Small Key (Ice Palace)
"Ice Palace - Map Chest": Map (Ice Palace)
"Ice Palace - Freezor Chest": Bombs (3)
"Ice Palace - Iced T Room": Small Key (Ice Palace)
"Ice Palace - Big Chest": Blue Mail
"Ice Palace - Boss": Boss Heart Container
"Ice Palace - Prize": Crystal 5
"Misery Mire - Main Lobby": Small Key (Misery Mire)
"Misery Mire - Big Chest": Cane of Somaria
"Misery Mire - Map Chest": Map (Misery Mire)
"Misery Mire - Spike Chest": Small Key (Misery Mire)
"Misery Mire - Bridge Chest": Small Key (Misery Mire)
"Misery Mire - Compass Chest": Compass (Misery Mire)
"Misery Mire - Big Key Chest": Big Key (Misery Mire)
"Misery Mire - Boss": Boss Heart Container
"Misery Mire - Prize": Crystal 6
"Turtle Rock - Compass Chest": Compass (Turtle Rock)
"Turtle Rock - Roller Room - Left": Map (Turtle Rock)
"Turtle Rock - Roller Room - Right": Small Key (Turtle Rock)
"Turtle Rock - Chain Chomps": Small Key (Turtle Rock)
"Turtle Rock - Big Key Chest": Big Key (Turtle Rock)
"Turtle Rock - Big Chest": Mirror Shield
"Turtle Rock - Crystaroller Room": Small Key (Turtle Rock)
"Turtle Rock - Eye Bridge - Bottom Left": Small Key (Turtle Rock)
"Turtle Rock - Eye Bridge - Bottom Right": Rupees (20)
"Turtle Rock - Eye Bridge - Top Left": Rupees (5)
"Turtle Rock - Eye Bridge - Top Right": Rupee (1)
"Turtle Rock - Boss": Boss Heart Container
"Turtle Rock - Prize": Crystal 2
"Ganons Tower - Bob's Torch": Small Key (Ganons Tower)
"Ganons Tower - Hope Room - Left": Arrows (10)
"Ganons Tower - Hope Room - Right": Bombs (3)
"Ganons Tower - Big Chest": Red Mail
"Ganons Tower - Bob's Chest": Arrows (10)
"Ganons Tower - Tile Room": Small Key (Ganons Tower)
"Ganons Tower - Compass Room - Top Left": Compass (Ganons Tower)
"Ganons Tower - Compass Room - Top Right": Rupee (1)
"Ganons Tower - Compass Room - Bottom Left": Rupees (20)
"Ganons Tower - Compass Room - Bottom Right": Arrows (10)
"Ganons Tower - Map Chest": Map (Ganons Tower)
"Ganons Tower - Firesnake Room": Small Key (Ganons Tower)
"Ganons Tower - DMs Room - Top Left": Bombs (3)
"Ganons Tower - DMs Room - Top Right": Arrows (10)
"Ganons Tower - DMs Room - Bottom Left": Bombs (3)
"Ganons Tower - DMs Room - Bottom Right": Rupees (20)
"Ganons Tower - Randomizer Room - Top Left": Arrows (10)
"Ganons Tower - Randomizer Room - Top Right": Arrows (10)
"Ganons Tower - Randomizer Room - Bottom Left": Bombs (3)
"Ganons Tower - Randomizer Room - Bottom Right": Bombs (3)
"Ganons Tower - Big Key Room - Left": Arrows (10)
"Ganons Tower - Big Key Room - Right": Bombs (3)
"Ganons Tower - Big Key Chest": Big Key (Ganons Tower)
"Ganons Tower - Mini Helmasaur Room - Left": Bombs (3)
"Ganons Tower - Mini Helmasaur Room - Right": Bombs (3)
"Ganons Tower - Pre-Moldorm Chest": Small Key (Ganons Tower)
"Ganons Tower - Validation Chest": Rupees (5)
medallions:
1:
"Misery Mire": Ether
"Turtle Rock": Quake