mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -06:00
Pokemon R/B: The Big Door Shuffle Update (#2861)
- Perhaps most critically, adds the ability for the door shuffle code to catch door shuffle exceptions and try again. Will try up to 10 times. Should mean Door Shuffle does not need to be disallowed in the big async🤞
- Door Shuffle code has been made drastically faster by searching for the first dead end instead of sorting the whole list of entrances by whether they are dead ends.
- Renames Full to Interiors, and adds a new Full door shuffle that shuffles interior-to-interior doors separately from exterior-to-interior doors.
- Adds a new Decoupled door shuffle.
- Warp Tile Shuffle now has 3 separate options, Vanilla, Shuffle, and Mixed. Shuffle shuffles the warp tiles among themselves, Mixed mixes them into the Door Shuffle pool.
- Safari Zone connections are now shuffled on Full, Insanity, and Decoupled.
- On Simple Door Shuffle, the Town Map is updated to show the new dungeon locations. The Town Map has been updated to show the locations of dungeons that previously were not shown unless you opened the map within them, and the Sea Cottage has been removed from it.
- Adds Auto Level Scaling that chooses the level scaling mode based on the Door Shuffle choice.
- Fixes issues with Flash and Fly move interventions (where it ensures an available Pokémon that can learn it is reachable depending on settings).
- Fixes a possible generation crash with type chart randomization.
- Should fix an issue where `stage_fill_hook` was able to remove the wrong item from the item pool resulting in a duplicated item reference existing.
- Adds a stage_post_fill function which searches for Pokémon in order of spheres, setting all but the first advancement Pokémon event found to `useful` so that spoiler playthrough calculation skips them. In a solo game gen test, this cut gen time from 15 seconds to 10 seconds with same seed number. Difference is likely to be much more massive in larger multiworlds.
This commit is contained in:
@@ -195,11 +195,11 @@ class PokemonRedBlueWorld(World):
|
||||
normals -= subtract_amounts[2]
|
||||
while super_effectives + not_very_effectives + normals > 225 - immunities:
|
||||
r = self.multiworld.random.randint(0, 2)
|
||||
if r == 0:
|
||||
if r == 0 and super_effectives:
|
||||
super_effectives -= 1
|
||||
elif r == 1:
|
||||
elif r == 1 and not_very_effectives:
|
||||
not_very_effectives -= 1
|
||||
else:
|
||||
elif normals:
|
||||
normals -= 1
|
||||
chart = []
|
||||
for matchup_list, matchup_value in zip([immunities, normals, super_effectives, not_very_effectives],
|
||||
@@ -249,14 +249,18 @@ class PokemonRedBlueWorld(World):
|
||||
itempool = progitempool + usefulitempool + filleritempool
|
||||
multiworld.random.shuffle(itempool)
|
||||
unplaced_items = []
|
||||
for item in itempool:
|
||||
for i, item in enumerate(itempool):
|
||||
if item.player == loc.player and loc.can_fill(multiworld.state, item, False):
|
||||
if item in progitempool:
|
||||
progitempool.remove(item)
|
||||
elif item in usefulitempool:
|
||||
usefulitempool.remove(item)
|
||||
elif item in filleritempool:
|
||||
filleritempool.remove(item)
|
||||
if item.advancement:
|
||||
pool = progitempool
|
||||
elif item.useful:
|
||||
pool = usefulitempool
|
||||
else:
|
||||
pool = filleritempool
|
||||
for i, check_item in enumerate(pool):
|
||||
if item is check_item:
|
||||
pool.pop(i)
|
||||
break
|
||||
if item.advancement:
|
||||
state = sweep_from_pool(multiworld.state, progitempool + unplaced_items)
|
||||
if (not item.advancement) or state.can_reach(loc, "Location", loc.player):
|
||||
@@ -416,16 +420,16 @@ class PokemonRedBlueWorld(World):
|
||||
self.multiworld.victory_road_condition[self.player])
|
||||
> 7) or (self.multiworld.door_shuffle[self.player] not in ("off", "simple")))):
|
||||
intervene_move = "Cut"
|
||||
elif ((not logic.can_learn_hm(test_state, "Flash", self.player)) and self.multiworld.dark_rock_tunnel_logic[self.player]
|
||||
and (((self.multiworld.accessibility[self.player] != "minimal" or
|
||||
(self.multiworld.trainersanity[self.player] or self.multiworld.extra_key_items[self.player])) or
|
||||
self.multiworld.door_shuffle[self.player]))):
|
||||
elif ((not logic.can_learn_hm(test_state, "Flash", self.player))
|
||||
and self.multiworld.dark_rock_tunnel_logic[self.player]
|
||||
and (self.multiworld.accessibility[self.player] != "minimal"
|
||||
or self.multiworld.door_shuffle[self.player])):
|
||||
intervene_move = "Flash"
|
||||
# If no Pokémon can learn Fly, then during door shuffle it would simply not treat the free fly maps
|
||||
# as reachable, and if on no door shuffle or simple, fly is simply never necessary.
|
||||
# We only intervene if a Pokémon is able to learn fly but none are reachable, as that would have been
|
||||
# considered in door shuffle.
|
||||
elif ((not logic.can_learn_hm(test_state, "Fly", self.player)) and logic.can_learn_hm(test_state, "Fly", self.player)
|
||||
elif ((not logic.can_learn_hm(test_state, "Fly", self.player))
|
||||
and self.multiworld.door_shuffle[self.player] not in
|
||||
("off", "simple") and [self.fly_map, self.town_map_fly_map] != ["Pallet Town", "Pallet Town"]):
|
||||
intervene_move = "Fly"
|
||||
@@ -554,23 +558,21 @@ class PokemonRedBlueWorld(World):
|
||||
else:
|
||||
raise Exception("Failed to remove corresponding item while deleting unreachable Dexsanity location")
|
||||
|
||||
|
||||
if self.multiworld.door_shuffle[self.player] == "decoupled":
|
||||
swept_state = self.multiworld.state.copy()
|
||||
swept_state.sweep_for_events(player=self.player)
|
||||
locations = [location for location in
|
||||
self.multiworld.get_reachable_locations(swept_state, self.player) if location.item is
|
||||
None]
|
||||
self.multiworld.random.shuffle(locations)
|
||||
while len(locations) > 10:
|
||||
location = locations.pop()
|
||||
location.progress_type = LocationProgressType.EXCLUDED
|
||||
|
||||
if self.multiworld.key_items_only[self.player]:
|
||||
locations = [location for location in self.multiworld.get_unfilled_locations(self.player) if
|
||||
location.progress_type == LocationProgressType.DEFAULT]
|
||||
for location in locations:
|
||||
location.progress_type = LocationProgressType.PRIORITY
|
||||
@classmethod
|
||||
def stage_post_fill(cls, multiworld):
|
||||
# Convert all but one of each instance of a wild Pokemon to useful classification.
|
||||
# This cuts down on time spent calculating the spoiler playthrough.
|
||||
found_mons = set()
|
||||
for sphere in multiworld.get_spheres():
|
||||
for location in sphere:
|
||||
if (location.game == "Pokemon Red and Blue" and (location.item.name in poke_data.pokemon_data.keys()
|
||||
or "Static " in location.item.name)
|
||||
and location.item.advancement):
|
||||
key = (location.player, location.item.name)
|
||||
if key in found_mons:
|
||||
location.item.classification = ItemClassification.useful
|
||||
else:
|
||||
found_mons.add(key)
|
||||
|
||||
def create_regions(self):
|
||||
if (self.multiworld.old_man[self.player] == "vanilla" or
|
||||
|
Reference in New Issue
Block a user