mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
LttP: extract Dungeon and Boss from core (#1787)
This commit is contained in:
@@ -226,40 +226,40 @@ for diff in {'easy', 'normal', 'hard', 'expert'}:
|
||||
|
||||
def generate_itempool(world):
|
||||
player = world.player
|
||||
world = world.multiworld
|
||||
multiworld = world.multiworld
|
||||
|
||||
if world.difficulty[player] not in difficulties:
|
||||
raise NotImplementedError(f"Diffulty {world.difficulty[player]}")
|
||||
if world.goal[player] not in {'ganon', 'pedestal', 'bosses', 'triforcehunt', 'localtriforcehunt', 'icerodhunt',
|
||||
if multiworld.difficulty[player] not in difficulties:
|
||||
raise NotImplementedError(f"Diffulty {multiworld.difficulty[player]}")
|
||||
if multiworld.goal[player] not in {'ganon', 'pedestal', 'bosses', 'triforcehunt', 'localtriforcehunt', 'icerodhunt',
|
||||
'ganontriforcehunt', 'localganontriforcehunt', 'crystals', 'ganonpedestal'}:
|
||||
raise NotImplementedError(f"Goal {world.goal[player]} for player {player}")
|
||||
if world.mode[player] not in {'open', 'standard', 'inverted'}:
|
||||
raise NotImplementedError(f"Mode {world.mode[player]} for player {player}")
|
||||
if world.timer[player] not in {False, 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'}:
|
||||
raise NotImplementedError(f"Timer {world.mode[player]} for player {player}")
|
||||
raise NotImplementedError(f"Goal {multiworld.goal[player]} for player {player}")
|
||||
if multiworld.mode[player] not in {'open', 'standard', 'inverted'}:
|
||||
raise NotImplementedError(f"Mode {multiworld.mode[player]} for player {player}")
|
||||
if multiworld.timer[player] not in {False, 'display', 'timed', 'timed-ohko', 'ohko', 'timed-countdown'}:
|
||||
raise NotImplementedError(f"Timer {multiworld.mode[player]} for player {player}")
|
||||
|
||||
if world.timer[player] in ['ohko', 'timed-ohko']:
|
||||
world.can_take_damage[player] = False
|
||||
if world.goal[player] in ['pedestal', 'triforcehunt', 'localtriforcehunt', 'icerodhunt']:
|
||||
world.push_item(world.get_location('Ganon', player), ItemFactory('Nothing', player), False)
|
||||
if multiworld.timer[player] in ['ohko', 'timed-ohko']:
|
||||
multiworld.can_take_damage[player] = False
|
||||
if multiworld.goal[player] in ['pedestal', 'triforcehunt', 'localtriforcehunt', 'icerodhunt']:
|
||||
multiworld.push_item(multiworld.get_location('Ganon', player), ItemFactory('Nothing', player), False)
|
||||
else:
|
||||
world.push_item(world.get_location('Ganon', player), ItemFactory('Triforce', player), False)
|
||||
multiworld.push_item(multiworld.get_location('Ganon', player), ItemFactory('Triforce', player), False)
|
||||
|
||||
if world.goal[player] == 'icerodhunt':
|
||||
world.progression_balancing[player].value = 0
|
||||
loc = world.get_location('Turtle Rock - Boss', player)
|
||||
world.push_item(loc, ItemFactory('Triforce Piece', player), False)
|
||||
world.treasure_hunt_count[player] = 1
|
||||
if world.boss_shuffle[player] != 'none':
|
||||
if isinstance(world.boss_shuffle[player].value, str) and 'turtle rock-' not in world.boss_shuffle[player].value:
|
||||
world.boss_shuffle[player] = LTTPBosses.from_text(f'Turtle Rock-Trinexx;{world.boss_shuffle[player].current_key}')
|
||||
elif isinstance(world.boss_shuffle[player].value, int):
|
||||
world.boss_shuffle[player] = LTTPBosses.from_text(f'Turtle Rock-Trinexx;{world.boss_shuffle[player].current_key}')
|
||||
if multiworld.goal[player] == 'icerodhunt':
|
||||
multiworld.progression_balancing[player].value = 0
|
||||
loc = multiworld.get_location('Turtle Rock - Boss', player)
|
||||
multiworld.push_item(loc, ItemFactory('Triforce Piece', player), False)
|
||||
multiworld.treasure_hunt_count[player] = 1
|
||||
if multiworld.boss_shuffle[player] != 'none':
|
||||
if isinstance(multiworld.boss_shuffle[player].value, str) and 'turtle rock-' not in multiworld.boss_shuffle[player].value:
|
||||
multiworld.boss_shuffle[player] = LTTPBosses.from_text(f'Turtle Rock-Trinexx;{multiworld.boss_shuffle[player].current_key}')
|
||||
elif isinstance(multiworld.boss_shuffle[player].value, int):
|
||||
multiworld.boss_shuffle[player] = LTTPBosses.from_text(f'Turtle Rock-Trinexx;{multiworld.boss_shuffle[player].current_key}')
|
||||
else:
|
||||
logging.warning(f'Cannot guarantee that Trinexx is the boss of Turtle Rock for player {player}')
|
||||
loc.event = True
|
||||
loc.locked = True
|
||||
itemdiff = difficulties[world.difficulty[player]]
|
||||
itemdiff = difficulties[multiworld.difficulty[player]]
|
||||
itempool = []
|
||||
itempool.extend(itemdiff.alwaysitems)
|
||||
itempool.remove('Ice Rod')
|
||||
@@ -270,7 +270,7 @@ def generate_itempool(world):
|
||||
itempool.extend(itemdiff.bottles)
|
||||
itempool.extend(itemdiff.basicbow)
|
||||
itempool.extend(itemdiff.basicarmor)
|
||||
if not world.swordless[player]:
|
||||
if not multiworld.swordless[player]:
|
||||
itempool.extend(itemdiff.basicsword)
|
||||
itempool.extend(itemdiff.basicmagic)
|
||||
itempool.extend(itemdiff.basicglove)
|
||||
@@ -279,28 +279,28 @@ def generate_itempool(world):
|
||||
itempool.extend(['Rupees (300)'] * 34)
|
||||
itempool.extend(['Bombs (10)'] * 5)
|
||||
itempool.extend(['Arrows (10)'] * 7)
|
||||
if world.smallkey_shuffle[player] == smallkey_shuffle.option_universal:
|
||||
if multiworld.smallkey_shuffle[player] == smallkey_shuffle.option_universal:
|
||||
itempool.extend(itemdiff.universal_keys)
|
||||
itempool.append('Small Key (Universal)')
|
||||
|
||||
for item in itempool:
|
||||
world.push_precollected(ItemFactory(item, player))
|
||||
multiworld.push_precollected(ItemFactory(item, player))
|
||||
|
||||
if world.goal[player] in ['triforcehunt', 'localtriforcehunt', 'icerodhunt']:
|
||||
region = world.get_region('Light World', player)
|
||||
if multiworld.goal[player] in ['triforcehunt', 'localtriforcehunt', 'icerodhunt']:
|
||||
region = multiworld.get_region('Light World', player)
|
||||
|
||||
loc = ALttPLocation(player, "Murahdahla", parent=region)
|
||||
loc.access_rule = lambda state: has_triforce_pieces(state, player)
|
||||
|
||||
region.locations.append(loc)
|
||||
world.clear_location_cache()
|
||||
multiworld.clear_location_cache()
|
||||
|
||||
world.push_item(loc, ItemFactory('Triforce', player), False)
|
||||
multiworld.push_item(loc, ItemFactory('Triforce', player), False)
|
||||
loc.event = True
|
||||
loc.locked = True
|
||||
|
||||
world.get_location('Ganon', player).event = True
|
||||
world.get_location('Ganon', player).locked = True
|
||||
multiworld.get_location('Ganon', player).event = True
|
||||
multiworld.get_location('Ganon', player).locked = True
|
||||
event_pairs = [
|
||||
('Agahnim 1', 'Beat Agahnim 1'),
|
||||
('Agahnim 2', 'Beat Agahnim 2'),
|
||||
@@ -312,26 +312,26 @@ def generate_itempool(world):
|
||||
('Flute Activation Spot', 'Activated Flute')
|
||||
]
|
||||
for location_name, event_name in event_pairs:
|
||||
location = world.get_location(location_name, player)
|
||||
location = multiworld.get_location(location_name, player)
|
||||
event = ItemFactory(event_name, player)
|
||||
world.push_item(location, event, False)
|
||||
multiworld.push_item(location, event, False)
|
||||
location.event = location.locked = True
|
||||
|
||||
|
||||
# set up item pool
|
||||
additional_triforce_pieces = 0
|
||||
if world.custom:
|
||||
if multiworld.custom:
|
||||
(pool, placed_items, precollected_items, clock_mode, treasure_hunt_count,
|
||||
treasure_hunt_icon) = make_custom_item_pool(world, player)
|
||||
world.rupoor_cost = min(world.customitemarray[67], 9999)
|
||||
treasure_hunt_icon) = 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, \
|
||||
treasure_hunt_icon, additional_triforce_pieces = get_pool_core(world, player)
|
||||
treasure_hunt_icon, additional_triforce_pieces = get_pool_core(multiworld, player)
|
||||
|
||||
for item in precollected_items:
|
||||
world.push_precollected(ItemFactory(item, player))
|
||||
multiworld.push_precollected(ItemFactory(item, player))
|
||||
|
||||
if world.mode[player] == 'standard' and not has_melee_weapon(world.state, player):
|
||||
if multiworld.mode[player] == 'standard' and not has_melee_weapon(multiworld.state, player):
|
||||
if "Link's Uncle" not in placed_items:
|
||||
found_sword = False
|
||||
found_bow = False
|
||||
@@ -347,60 +347,60 @@ def generate_itempool(world):
|
||||
if item in ['Hammer', 'Bombs (10)', 'Fire Rod', 'Cane of Somaria', 'Cane of Byrna']:
|
||||
if item not in possible_weapons:
|
||||
possible_weapons.append(item)
|
||||
starting_weapon = world.random.choice(possible_weapons)
|
||||
starting_weapon = multiworld.random.choice(possible_weapons)
|
||||
placed_items["Link's Uncle"] = starting_weapon
|
||||
pool.remove(starting_weapon)
|
||||
if placed_items["Link's Uncle"] in ['Bow', 'Progressive Bow', 'Bombs (10)', 'Cane of Somaria', 'Cane of Byrna'] and world.enemy_health[player] not in ['default', 'easy']:
|
||||
world.escape_assist[player].append('bombs')
|
||||
if placed_items["Link's Uncle"] in ['Bow', 'Progressive Bow', 'Bombs (10)', 'Cane of Somaria', 'Cane of Byrna'] and multiworld.enemy_health[player] not in ['default', 'easy']:
|
||||
multiworld.escape_assist[player].append('bombs')
|
||||
|
||||
for (location, item) in placed_items.items():
|
||||
world.get_location(location, player).place_locked_item(ItemFactory(item, player))
|
||||
multiworld.get_location(location, player).place_locked_item(ItemFactory(item, player))
|
||||
|
||||
items = ItemFactory(pool, player)
|
||||
# convert one Progressive Bow into Progressive Bow (Alt), in ID only, for ganon silvers hint text
|
||||
if world.worlds[player].has_progressive_bows:
|
||||
if multiworld.worlds[player].has_progressive_bows:
|
||||
for item in items:
|
||||
if item.code == 0x64: # Progressive Bow
|
||||
item.code = 0x65 # Progressive Bow (Alt)
|
||||
break
|
||||
|
||||
if clock_mode is not None:
|
||||
world.clock_mode[player] = clock_mode
|
||||
multiworld.clock_mode[player] = clock_mode
|
||||
|
||||
if treasure_hunt_count is not None:
|
||||
world.treasure_hunt_count[player] = treasure_hunt_count % 999
|
||||
multiworld.treasure_hunt_count[player] = treasure_hunt_count % 999
|
||||
if treasure_hunt_icon is not None:
|
||||
world.treasure_hunt_icon[player] = treasure_hunt_icon
|
||||
multiworld.treasure_hunt_icon[player] = treasure_hunt_icon
|
||||
|
||||
dungeon_items = [item for item in get_dungeon_item_pool_player(world, player)
|
||||
if item.name not in world.worlds[player].dungeon_local_item_names]
|
||||
dungeon_item_replacements = difficulties[world.difficulty[player]].extras[0]\
|
||||
+ difficulties[world.difficulty[player]].extras[1]\
|
||||
+ difficulties[world.difficulty[player]].extras[2]\
|
||||
+ difficulties[world.difficulty[player]].extras[3]\
|
||||
+ difficulties[world.difficulty[player]].extras[4]
|
||||
world.random.shuffle(dungeon_item_replacements)
|
||||
if world.goal[player] == 'icerodhunt':
|
||||
dungeon_items = [item for item in get_dungeon_item_pool_player(world)
|
||||
if item.name not in multiworld.worlds[player].dungeon_local_item_names]
|
||||
dungeon_item_replacements = difficulties[multiworld.difficulty[player]].extras[0]\
|
||||
+ difficulties[multiworld.difficulty[player]].extras[1]\
|
||||
+ difficulties[multiworld.difficulty[player]].extras[2]\
|
||||
+ difficulties[multiworld.difficulty[player]].extras[3]\
|
||||
+ difficulties[multiworld.difficulty[player]].extras[4]
|
||||
multiworld.random.shuffle(dungeon_item_replacements)
|
||||
if multiworld.goal[player] == 'icerodhunt':
|
||||
for item in dungeon_items:
|
||||
world.itempool.append(ItemFactory(GetBeemizerItem(world, player, 'Nothing'), player))
|
||||
world.push_precollected(item)
|
||||
multiworld.itempool.append(ItemFactory(GetBeemizerItem(multiworld, player, 'Nothing'), player))
|
||||
multiworld.push_precollected(item)
|
||||
else:
|
||||
for x in range(len(dungeon_items)-1, -1, -1):
|
||||
item = dungeon_items[x]
|
||||
if ((world.smallkey_shuffle[player] == smallkey_shuffle.option_start_with and item.type == 'SmallKey')
|
||||
or (world.bigkey_shuffle[player] == bigkey_shuffle.option_start_with and item.type == 'BigKey')
|
||||
or (world.compass_shuffle[player] == compass_shuffle.option_start_with and item.type == 'Compass')
|
||||
or (world.map_shuffle[player] == map_shuffle.option_start_with and item.type == 'Map')):
|
||||
if ((multiworld.smallkey_shuffle[player] == smallkey_shuffle.option_start_with and item.type == 'SmallKey')
|
||||
or (multiworld.bigkey_shuffle[player] == bigkey_shuffle.option_start_with and item.type == 'BigKey')
|
||||
or (multiworld.compass_shuffle[player] == compass_shuffle.option_start_with and item.type == 'Compass')
|
||||
or (multiworld.map_shuffle[player] == map_shuffle.option_start_with and item.type == 'Map')):
|
||||
dungeon_items.remove(item)
|
||||
world.push_precollected(item)
|
||||
world.itempool.append(ItemFactory(dungeon_item_replacements.pop(), player))
|
||||
world.itempool.extend([item for item in dungeon_items])
|
||||
multiworld.push_precollected(item)
|
||||
multiworld.itempool.append(ItemFactory(dungeon_item_replacements.pop(), player))
|
||||
multiworld.itempool.extend([item for item in dungeon_items])
|
||||
# logic has some branches where having 4 hearts is one possible requirement (of several alternatives)
|
||||
# rather than making all hearts/heart pieces progression items (which slows down generation considerably)
|
||||
# We mark one random heart container as an advancement item (or 4 heart pieces in expert mode)
|
||||
if world.goal[player] != 'icerodhunt' and world.difficulty[player] in ['easy', 'normal', 'hard'] and not (world.custom and world.customitemarray[30] == 0):
|
||||
if multiworld.goal[player] != 'icerodhunt' and multiworld.difficulty[player] in ['easy', 'normal', 'hard'] and not (multiworld.custom and multiworld.customitemarray[30] == 0):
|
||||
next(item for item in items if item.name == 'Boss Heart Container').classification = ItemClassification.progression
|
||||
elif world.goal[player] != 'icerodhunt' and world.difficulty[player] in ['expert'] and not (world.custom and world.customitemarray[29] < 4):
|
||||
elif multiworld.goal[player] != 'icerodhunt' and multiworld.difficulty[player] in ['expert'] and not (multiworld.custom and multiworld.customitemarray[29] < 4):
|
||||
adv_heart_pieces = (item for item in items if item.name == 'Piece of Heart')
|
||||
for i in range(4):
|
||||
next(adv_heart_pieces).classification = ItemClassification.progression
|
||||
@@ -412,41 +412,41 @@ def generate_itempool(world):
|
||||
if item.advancement or item.type:
|
||||
progressionitems.append(item)
|
||||
else:
|
||||
nonprogressionitems.append(GetBeemizerItem(world, item.player, item))
|
||||
world.random.shuffle(nonprogressionitems)
|
||||
nonprogressionitems.append(GetBeemizerItem(multiworld, item.player, item))
|
||||
multiworld.random.shuffle(nonprogressionitems)
|
||||
|
||||
if additional_triforce_pieces:
|
||||
if additional_triforce_pieces > len(nonprogressionitems):
|
||||
raise FillError(f"Not enough non-progression items to replace with Triforce pieces found for player "
|
||||
f"{world.get_player_name(player)}.")
|
||||
f"{multiworld.get_player_name(player)}.")
|
||||
progressionitems += [ItemFactory("Triforce Piece", player) for _ in range(additional_triforce_pieces)]
|
||||
nonprogressionitems.sort(key=lambda item: int("Heart" in item.name)) # try to keep hearts in the pool
|
||||
nonprogressionitems = nonprogressionitems[additional_triforce_pieces:]
|
||||
world.random.shuffle(nonprogressionitems)
|
||||
multiworld.random.shuffle(nonprogressionitems)
|
||||
|
||||
# shuffle medallions
|
||||
if world.required_medallions[player][0] == "random":
|
||||
mm_medallion = world.random.choice(['Ether', 'Quake', 'Bombos'])
|
||||
if multiworld.required_medallions[player][0] == "random":
|
||||
mm_medallion = multiworld.random.choice(['Ether', 'Quake', 'Bombos'])
|
||||
else:
|
||||
mm_medallion = world.required_medallions[player][0]
|
||||
if world.required_medallions[player][1] == "random":
|
||||
tr_medallion = world.random.choice(['Ether', 'Quake', 'Bombos'])
|
||||
mm_medallion = multiworld.required_medallions[player][0]
|
||||
if multiworld.required_medallions[player][1] == "random":
|
||||
tr_medallion = multiworld.random.choice(['Ether', 'Quake', 'Bombos'])
|
||||
else:
|
||||
tr_medallion = world.required_medallions[player][1]
|
||||
world.required_medallions[player] = (mm_medallion, tr_medallion)
|
||||
tr_medallion = multiworld.required_medallions[player][1]
|
||||
multiworld.required_medallions[player] = (mm_medallion, tr_medallion)
|
||||
|
||||
place_bosses(world, player)
|
||||
set_up_shops(world, player)
|
||||
place_bosses(world)
|
||||
set_up_shops(multiworld, player)
|
||||
|
||||
if world.shop_shuffle[player]:
|
||||
shuffle_shops(world, nonprogressionitems, player)
|
||||
if multiworld.shop_shuffle[player]:
|
||||
shuffle_shops(multiworld, nonprogressionitems, player)
|
||||
|
||||
world.itempool += progressionitems + nonprogressionitems
|
||||
multiworld.itempool += progressionitems + nonprogressionitems
|
||||
|
||||
if world.retro_caves[player]:
|
||||
set_up_take_anys(world, player) # depends on world.itempool to be set
|
||||
if multiworld.retro_caves[player]:
|
||||
set_up_take_anys(multiworld, player) # depends on world.itempool to be set
|
||||
# set_up_take_anys needs to run first
|
||||
create_dynamic_shop_locations(world, player)
|
||||
create_dynamic_shop_locations(multiworld, player)
|
||||
|
||||
|
||||
take_any_locations = {
|
||||
|
||||
Reference in New Issue
Block a user