Skip to content

Commit

Permalink
ALTTP: 0.4.6 fixes (ArchipelagoMW#3215)
Browse files Browse the repository at this point in the history
* Fix randomizer room logic

* Fix Triforce Hunt HUD always present

* Fix Circle of Pots enemy byte

* treasure_hunt_total for Murahdala text
  • Loading branch information
Alchav authored Apr 27, 2024
1 parent 9e20fa4 commit 9afe451
Show file tree
Hide file tree
Showing 13 changed files with 49 additions and 39 deletions.
33 changes: 19 additions & 14 deletions worlds/alttp/ItemPool.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -679,20 +682,21 @@ def place_item(loc, item):
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):
Expand Down Expand Up @@ -733,7 +737,7 @@ def place_item(loc, item):
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)


Expand All @@ -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"
Expand Down Expand Up @@ -844,7 +849,7 @@ def place_item(loc, item):
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'
Expand Down Expand Up @@ -889,4 +894,4 @@ def place_item(loc, item):
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)
20 changes: 10 additions & 10 deletions worlds/alttp/Rom.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -1269,7 +1269,7 @@ def chunk(l, n):
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)

Expand Down Expand Up @@ -2482,16 +2482,16 @@ def hint_text(dest, ped_hint=False):
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.'
Expand All @@ -2500,20 +2500,20 @@ def hint_text(dest, ped_hint=False):
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)]

Expand Down
4 changes: 2 additions & 2 deletions worlds/alttp/Rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/StateHelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
3 changes: 2 additions & 1 deletion worlds/alttp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ def enemizer_path(self) -> str:
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()
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/test/dungeons/TestDungeon.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def setUp(self):
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)
Expand Down
12 changes: 8 additions & 4 deletions worlds/alttp/test/dungeons/TestGanonsTower.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,26 @@ def testGanonsTower(self):
["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']],
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/test/inverted/TestInverted.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def setUp(self):
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def setUp(self):
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()
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/test/inverted_owg/TestInvertedOWG.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def setUp(self):
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()
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/test/minor_glitches/TestMinor.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def setUp(self):
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()
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/test/owg/TestVanillaOWG.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def setUp(self):
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()
Expand Down
2 changes: 1 addition & 1 deletion worlds/alttp/test/vanilla/TestVanilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def setUp(self):
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()
Expand Down

0 comments on commit 9afe451

Please sign in to comment.