Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
gaithern authored Apr 28, 2024
2 parents 6c5e8fc + 9cdc905 commit 5390622
Show file tree
Hide file tree
Showing 17 changed files with 62 additions and 44 deletions.
7 changes: 5 additions & 2 deletions WebHostLib/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ def process_multidata(compressed_multidata, files={}):
game_data = games_package_schema.validate(game_data)
game_data = {key: value for key, value in sorted(game_data.items())}
game_data["checksum"] = data_package_checksum(game_data)
game_data_package = GameDataPackage(checksum=game_data["checksum"],
data=pickle.dumps(game_data))
if original_checksum != game_data["checksum"]:
raise Exception(f"Original checksum {original_checksum} != "
f"calculated checksum {game_data['checksum']} "
f"for game {game}.")

game_data_package = GameDataPackage(checksum=game_data["checksum"],
data=pickle.dumps(game_data))
decompressed_multidata["datapackage"][game] = {
"version": game_data.get("version", 0),
"checksum": game_data["checksum"],
Expand Down Expand Up @@ -192,6 +193,8 @@ def uploads():
res = upload_zip_to_db(zfile)
except VersionException:
flash(f"Could not load multidata. Wrong Version detected.")
except Exception as e:
flash(f"Could not load multidata. File may be corrupted or incompatible. ({e})")
else:
if res is str:
return res
Expand Down
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
Loading

0 comments on commit 5390622

Please sign in to comment.