ALTTP: 0.4.6 fixes (#3215)

* Fix randomizer room logic

* Fix Triforce Hunt HUD always present

* Fix Circle of Pots enemy byte

* treasure_hunt_total for Murahdala text
This commit is contained in:
Alchav 2024-04-27 19:48:59 -04:00 committed by GitHub
parent 9e20fa48e1
commit 9afe45166c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 49 additions and 39 deletions

View File

@ -276,13 +276,14 @@ def generate_itempool(world):
# set up item pool
additional_triforce_pieces = 0
treasure_hunt_total = 0
if multiworld.custom:
pool, placed_items, precollected_items, clock_mode, treasure_hunt_count = (
pool, placed_items, precollected_items, clock_mode, treasure_hunt_required = (
make_custom_item_pool(multiworld, player))
multiworld.rupoor_cost = min(multiworld.customitemarray[67], 9999)
else:
pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, additional_triforce_pieces = (
get_pool_core(multiworld, player))
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_required, treasure_hunt_total,
additional_triforce_pieces) = get_pool_core(multiworld, player)
for item in precollected_items:
multiworld.push_precollected(item_factory(item, world))
@ -337,7 +338,8 @@ def generate_itempool(world):
if clock_mode:
world.clock_mode = clock_mode
multiworld.worlds[player].treasure_hunt_count = treasure_hunt_count % 999
multiworld.worlds[player].treasure_hunt_required = treasure_hunt_required % 999
multiworld.worlds[player].treasure_hunt_total = treasure_hunt_total
dungeon_items = [item for item in get_dungeon_item_pool_player(world)
if item.name not in multiworld.worlds[player].dungeon_local_item_names]
@ -590,7 +592,8 @@ def get_pool_core(world, player: int):
placed_items = {}
precollected_items = []
clock_mode: str = ""
treasure_hunt_count: int = 1
treasure_hunt_required: int = 0
treasure_hunt_total: int = 0
diff = difficulties[difficulty]
pool.extend(diff.alwaysitems)
@ -679,20 +682,21 @@ def get_pool_core(world, player: int):
if 'triforce_hunt' in goal:
if world.triforce_pieces_mode[player].value == TriforcePiecesMode.option_extra:
triforce_pieces = world.triforce_pieces_available[player].value + world.triforce_pieces_extra[player].value
treasure_hunt_total = (world.triforce_pieces_available[player].value
+ world.triforce_pieces_extra[player].value)
elif world.triforce_pieces_mode[player].value == TriforcePiecesMode.option_percentage:
percentage = float(world.triforce_pieces_percentage[player].value) / 100
triforce_pieces = int(round(world.triforce_pieces_required[player].value * percentage, 0))
treasure_hunt_total = int(round(world.triforce_pieces_required[player].value * percentage, 0))
else: # available
triforce_pieces = world.triforce_pieces_available[player].value
treasure_hunt_total = world.triforce_pieces_available[player].value
triforce_pieces = min(90, max(triforce_pieces, world.triforce_pieces_required[player].value))
triforce_pieces = min(90, max(treasure_hunt_total, world.triforce_pieces_required[player].value))
pieces_in_core = min(extraitems, triforce_pieces)
additional_pieces_to_place = triforce_pieces - pieces_in_core
pool.extend(["Triforce Piece"] * pieces_in_core)
extraitems -= pieces_in_core
treasure_hunt_count = world.triforce_pieces_required[player].value
treasure_hunt_required = world.triforce_pieces_required[player].value
for extra in diff.extras:
if extraitems >= len(extra):
@ -733,7 +737,7 @@ def get_pool_core(world, player: int):
place_item(key_location, "Small Key (Universal)")
pool = pool[:-3]
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count,
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_required, treasure_hunt_total,
additional_pieces_to_place)
@ -749,7 +753,8 @@ def make_custom_item_pool(world, player):
placed_items = {}
precollected_items = []
clock_mode: str = ""
treasure_hunt_count: int = 1
treasure_hunt_required: int = 0
treasure_hunt_total: int = 0
def place_item(loc, item):
assert loc not in placed_items, "cannot place item twice"
@ -844,7 +849,7 @@ def make_custom_item_pool(world, player):
if "triforce" in world.goal[player]:
pool.extend(["Triforce Piece"] * world.triforce_pieces_available[player])
itemtotal += world.triforce_pieces_available[player]
treasure_hunt_count = world.triforce_pieces_required[player]
treasure_hunt_required = world.triforce_pieces_required[player]
if timer in ['display', 'timed', 'timed_countdown']:
clock_mode = 'countdown' if timer == 'timed_countdown' else 'stopwatch'
@ -889,4 +894,4 @@ def make_custom_item_pool(world, player):
pool.extend(['Nothing'] * (total_items_to_place - itemtotal))
logging.warning(f"Pool was filled up with {total_items_to_place - itemtotal} Nothing's for player {player}")
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count)
return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_required)

View File

@ -433,7 +433,7 @@ def patch_enemizer(world, rom: LocalRom, enemizercli, output_directory):
if multiworld.key_drop_shuffle[player]:
key_drop_enemies = {
0x4DA20, 0x4DA5C, 0x4DB7F, 0x4DD73, 0x4DDC3, 0x4DE07, 0x4E201,
0x4E20A, 0x4E326, 0x4E4F7, 0x4E686, 0x4E70C, 0x4E7C8, 0x4E7FA
0x4E20A, 0x4E326, 0x4E4F7, 0x4E687, 0x4E70C, 0x4E7C8, 0x4E7FA
}
for enemy in key_drop_enemies:
if rom.read_byte(enemy) == 0x12:
@ -1269,7 +1269,7 @@ def patch_rom(world: MultiWorld, rom: LocalRom, player: int, enemized: bool):
rom.write_int32(0x18020C, 0) # starting time (in frames, sint32)
# set up goals for treasure hunt
rom.write_int16(0x180163, local_world.treasure_hunt_count)
rom.write_int16(0x180163, local_world.treasure_hunt_required)
rom.write_bytes(0x180165, [0x0E, 0x28]) # Triforce Piece Sprite
rom.write_byte(0x180194, 1) # Must turn in triforced pieces (instant win not enabled)
@ -2482,16 +2482,16 @@ def write_strings(rom, world, player):
tt['sign_ganon'] = 'Go find the Triforce pieces with your friends... Ganon is invincible!'
else:
tt['sign_ganon'] = 'Go find the Triforce pieces... Ganon is invincible!'
if w.treasure_hunt_count > 1:
if w.treasure_hunt_required > 1:
tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\n" \
"invisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\n" \
"hidden in a hollow tree. If you bring\n%d Triforce pieces out of %d, I can reassemble it." % \
(w.treasure_hunt_count, world.triforce_pieces_available[player])
(w.treasure_hunt_required, w.treasure_hunt_total)
else:
tt['murahdahla'] = "Hello @. I\nam Murahdahla, brother of\nSahasrahla and Aginah. Behold the power of\n" \
"invisibility.\n\n\n\n… … …\n\nWait! you can see me? I knew I should have\n" \
"hidden in a hollow tree. If you bring\n%d Triforce piece out of %d, I can reassemble it." % \
(w.treasure_hunt_count, world.triforce_pieces_available[player])
(w.treasure_hunt_required, w.treasure_hunt_total)
elif world.goal[player] in ['pedestal']:
tt['ganon_fall_in_alt'] = 'Why are you even here?\n You can\'t even hurt me! Your goal is at the pedestal.'
tt['ganon_phase_3_alt'] = 'Seriously? Go Away, I will not Die.'
@ -2500,20 +2500,20 @@ def write_strings(rom, world, player):
tt['ganon_fall_in'] = Ganon1_texts[local_random.randint(0, len(Ganon1_texts) - 1)]
tt['ganon_fall_in_alt'] = 'You cannot defeat me until you finish your goal!'
tt['ganon_phase_3_alt'] = 'Got wax in\nyour ears?\nI can not die!'
if w.treasure_hunt_count > 1:
if w.treasure_hunt_required > 1:
if world.goal[player] == 'ganon_triforce_hunt' and world.players > 1:
tt['sign_ganon'] = 'You need to find %d Triforce pieces out of %d with your friends to defeat Ganon.' % \
(w.treasure_hunt_count, world.triforce_pieces_available[player])
(w.treasure_hunt_required, w.treasure_hunt_total)
elif world.goal[player] in ['ganon_triforce_hunt', 'local_ganon_triforce_hunt']:
tt['sign_ganon'] = 'You need to find %d Triforce pieces out of %d to defeat Ganon.' % \
(w.treasure_hunt_count, world.triforce_pieces_available[player])
(w.treasure_hunt_required, w.treasure_hunt_total)
else:
if world.goal[player] == 'ganon_triforce_hunt' and world.players > 1:
tt['sign_ganon'] = 'You need to find %d Triforce piece out of %d with your friends to defeat Ganon.' % \
(w.treasure_hunt_count, world.triforce_pieces_available[player])
(w.treasure_hunt_required, w.treasure_hunt_total)
elif world.goal[player] in ['ganon_triforce_hunt', 'local_ganon_triforce_hunt']:
tt['sign_ganon'] = 'You need to find %d Triforce piece out of %d to defeat Ganon.' % \
(w.treasure_hunt_count, world.triforce_pieces_available[player])
(w.treasure_hunt_required, w.treasure_hunt_total)
tt['kakariko_tavern_fisherman'] = TavernMan_texts[local_random.randint(0, len(TavernMan_texts) - 1)]

View File

@ -554,8 +554,8 @@ def global_rules(multiworld: MultiWorld, player: int):
set_rule(multiworld.get_location('Ganons Tower - Firesnake Room', player), lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 7) or
((item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) or item_name_in_location_names(state, 'Small Key (Ganons Tower)', player, [('Ganons Tower - Firesnake Room', player)])) and state._lttp_has_key('Small Key (Ganons Tower)', player, 5)))
for location in randomizer_room_chests:
set_rule(multiworld.get_location(location, player), lambda state: state._lttp_has_key('Small Key (Ganons Tower)', player, 8) or (
item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) and state._lttp_has_key('Small Key (Ganons Tower)', player, 6)))
set_rule(multiworld.get_location(location, player), lambda state: can_use_bombs(state, player) and (state._lttp_has_key('Small Key (Ganons Tower)', player, 8) or (
item_name_in_location_names(state, 'Big Key (Ganons Tower)', player, zip(randomizer_room_chests, [player] * len(randomizer_room_chests))) and state._lttp_has_key('Small Key (Ganons Tower)', player, 6))))
# Once again it is possible to need more than 7 keys...
set_rule(multiworld.get_entrance('Ganons Tower (Tile Room) Key Door', player), lambda state: state.has('Fire Rod', player) and (state._lttp_has_key('Small Key (Ganons Tower)', player, 7) or (

View File

@ -30,7 +30,7 @@ def can_shoot_arrows(state: CollectionState, player: int) -> bool:
def has_triforce_pieces(state: CollectionState, player: int) -> bool:
count = state.multiworld.worlds[player].treasure_hunt_count
count = state.multiworld.worlds[player].treasure_hunt_required
return state.count('Triforce Piece', player) + state.count('Power Star', player) >= count

View File

@ -261,7 +261,8 @@ class ALTTPWorld(World):
fix_fake_world: bool = True
clock_mode: str = ""
treasure_hunt_count: int = 1
treasure_hunt_required: int = 0
treasure_hunt_total: int = 0
def __init__(self, *args, **kwargs):
self.dungeon_local_item_names = set()

View File

@ -15,7 +15,7 @@ class TestDungeon(LTTPTestBase):
self.remove_exits = [] # Block dungeon exits
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
self.multiworld.bombless_start[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = 2
create_regions(self.multiworld, 1)
self.multiworld.worlds[1].create_dungeons()
create_shops(self.multiworld, 1)

View File

@ -33,22 +33,26 @@ class TestGanonsTower(TestDungeon):
["Ganons Tower - Randomizer Room - Top Left", False, []],
["Ganons Tower - Randomizer Room - Top Left", False, [], ['Hammer']],
["Ganons Tower - Randomizer Room - Top Left", False, [], ['Hookshot']],
["Ganons Tower - Randomizer Room - Top Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']],
["Ganons Tower - Randomizer Room - Top Left", False, [], ['Bomb Upgrade (50)']],
["Ganons Tower - Randomizer Room - Top Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']],
["Ganons Tower - Randomizer Room - Top Right", False, []],
["Ganons Tower - Randomizer Room - Top Right", False, [], ['Hammer']],
["Ganons Tower - Randomizer Room - Top Right", False, [], ['Hookshot']],
["Ganons Tower - Randomizer Room - Top Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']],
["Ganons Tower - Randomizer Room - Top Right", False, [], ['Bomb Upgrade (50)']],
["Ganons Tower - Randomizer Room - Top Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']],
["Ganons Tower - Randomizer Room - Bottom Left", False, []],
["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Hammer']],
["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Hookshot']],
["Ganons Tower - Randomizer Room - Bottom Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']],
["Ganons Tower - Randomizer Room - Bottom Left", False, [], ['Bomb Upgrade (50)']],
["Ganons Tower - Randomizer Room - Bottom Left", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']],
["Ganons Tower - Randomizer Room - Bottom Right", False, []],
["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Hammer']],
["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Hookshot']],
["Ganons Tower - Randomizer Room - Bottom Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer']],
["Ganons Tower - Randomizer Room - Bottom Right", False, [], ['Bomb Upgrade (50)']],
["Ganons Tower - Randomizer Room - Bottom Right", True, ['Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Small Key (Ganons Tower)', 'Hookshot', 'Hammer', 'Bomb Upgrade (50)']],
["Ganons Tower - Firesnake Room", False, []],
["Ganons Tower - Firesnake Room", False, [], ['Hammer']],

View File

@ -16,7 +16,7 @@ class TestInverted(TestBase, LTTPTestBase):
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
self.multiworld.mode[1].value = 2
self.multiworld.bombless_start[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = 2
create_inverted_regions(self.multiworld, 1)
self.world.create_dungeons()
create_shops(self.multiworld, 1)

View File

@ -17,7 +17,7 @@ class TestInvertedMinor(TestBase, LTTPTestBase):
self.multiworld.mode[1].value = 2
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("minor_glitches")
self.multiworld.bombless_start[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = 2
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
create_inverted_regions(self.multiworld, 1)
self.world.create_dungeons()

View File

@ -17,7 +17,7 @@ class TestInvertedOWG(TestBase, LTTPTestBase):
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("overworld_glitches")
self.multiworld.mode[1].value = 2
self.multiworld.bombless_start[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = 2
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
create_inverted_regions(self.multiworld, 1)
self.world.create_dungeons()

View File

@ -13,7 +13,7 @@ class TestMinor(TestBase, LTTPTestBase):
self.world_setup()
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("minor_glitches")
self.multiworld.bombless_start[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = 2
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
self.world.er_seed = 0
self.world.create_regions()

View File

@ -14,7 +14,7 @@ class TestVanillaOWG(TestBase, LTTPTestBase):
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("overworld_glitches")
self.multiworld.bombless_start[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = 2
self.multiworld.worlds[1].er_seed = 0
self.multiworld.worlds[1].create_regions()
self.multiworld.worlds[1].create_items()

View File

@ -13,7 +13,7 @@ class TestVanilla(TestBase, LTTPTestBase):
self.multiworld.glitches_required[1] = GlitchesRequired.from_any("no_glitches")
self.multiworld.worlds[1].difficulty_requirements = difficulties['normal']
self.multiworld.bombless_start[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = True
self.multiworld.shuffle_capacity_upgrades[1].value = 2
self.multiworld.worlds[1].er_seed = 0
self.multiworld.worlds[1].create_regions()
self.multiworld.worlds[1].create_items()