mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Pokemon Emerald: Rework tags/dynamically create item and location groups (#3263)
* Pokemon Emerald: Rework location tags to categories * Pokemon Emerald: Rework item tags, automatically create item/location groups * Pokemon Emerald: Move item and location groups to data.py, add some regional location groups * Map Regions * Pokemon Emerald: Fix up location groups * Pokemon Emerald: Move groups to their own file * Pokemon Emerald: Add meta groups for location groups * Pokemon Emerald: Fix has_group using updated item group name * Pokemon Emerald: Add sanity check for maps in location groups * Pokemon Emerald: Remove missed use of location.tags * Pokemon Emerald: Reclassify white and black flutes * Pokemon Emerald: Update changelog * Pokemon Emerald: Adjust changelog --------- Co-authored-by: Tsukino <16899482+Tsukino-uwu@users.noreply.github.com>
This commit is contained in:
@@ -15,11 +15,11 @@ import settings
|
||||
from worlds.AutoWorld import WebWorld, World
|
||||
|
||||
from .client import PokemonEmeraldClient # Unused, but required to register with BizHawkClient
|
||||
from .data import LEGENDARY_POKEMON, MapData, SpeciesData, TrainerData, data as emerald_data
|
||||
from .items import (ITEM_GROUPS, PokemonEmeraldItem, create_item_label_to_code_map, get_item_classification,
|
||||
offset_item_value)
|
||||
from .locations import (LOCATION_GROUPS, PokemonEmeraldLocation, create_location_label_to_id_map,
|
||||
create_locations_with_tags, set_free_fly, set_legendary_cave_entrances)
|
||||
from .data import LEGENDARY_POKEMON, MapData, SpeciesData, TrainerData, LocationCategory, data as emerald_data
|
||||
from .groups import ITEM_GROUPS, LOCATION_GROUPS
|
||||
from .items import PokemonEmeraldItem, create_item_label_to_code_map, get_item_classification, offset_item_value
|
||||
from .locations import (PokemonEmeraldLocation, create_location_label_to_id_map, create_locations_by_category,
|
||||
set_free_fly, set_legendary_cave_entrances)
|
||||
from .opponents import randomize_opponent_parties
|
||||
from .options import (Goal, DarkCavesRequireFlash, HmRequirements, ItemPoolType, PokemonEmeraldOptions,
|
||||
RandomizeWildPokemon, RandomizeBadges, RandomizeHms, NormanRequirement)
|
||||
@@ -133,9 +133,10 @@ class PokemonEmeraldWorld(World):
|
||||
|
||||
@classmethod
|
||||
def stage_assert_generate(cls, multiworld: MultiWorld) -> None:
|
||||
from .sanity_check import validate_regions
|
||||
from .sanity_check import validate_regions, validate_group_maps
|
||||
|
||||
assert validate_regions()
|
||||
assert validate_group_maps()
|
||||
|
||||
def get_filler_item_name(self) -> str:
|
||||
return "Great Ball"
|
||||
@@ -237,24 +238,32 @@ class PokemonEmeraldWorld(World):
|
||||
|
||||
def create_regions(self) -> None:
|
||||
from .regions import create_regions
|
||||
regions = create_regions(self)
|
||||
all_regions = create_regions(self)
|
||||
|
||||
tags = {"Badge", "HM", "KeyItem", "Rod", "Bike", "EventTicket"} # Tags with progression items always included
|
||||
# Categories with progression items always included
|
||||
categories = {
|
||||
LocationCategory.BADGE,
|
||||
LocationCategory.HM,
|
||||
LocationCategory.KEY,
|
||||
LocationCategory.ROD,
|
||||
LocationCategory.BIKE,
|
||||
LocationCategory.TICKET
|
||||
}
|
||||
if self.options.overworld_items:
|
||||
tags.add("OverworldItem")
|
||||
categories.add(LocationCategory.OVERWORLD_ITEM)
|
||||
if self.options.hidden_items:
|
||||
tags.add("HiddenItem")
|
||||
categories.add(LocationCategory.HIDDEN_ITEM)
|
||||
if self.options.npc_gifts:
|
||||
tags.add("NpcGift")
|
||||
categories.add(LocationCategory.GIFT)
|
||||
if self.options.berry_trees:
|
||||
tags.add("BerryTree")
|
||||
categories.add(LocationCategory.BERRY_TREE)
|
||||
if self.options.dexsanity:
|
||||
tags.add("Pokedex")
|
||||
categories.add(LocationCategory.POKEDEX)
|
||||
if self.options.trainersanity:
|
||||
tags.add("Trainer")
|
||||
create_locations_with_tags(self, regions, tags)
|
||||
categories.add(LocationCategory.TRAINER)
|
||||
create_locations_by_category(self, all_regions, categories)
|
||||
|
||||
self.multiworld.regions.extend(regions.values())
|
||||
self.multiworld.regions.extend(all_regions.values())
|
||||
|
||||
# Exclude locations which are always locked behind the player's goal
|
||||
def exclude_locations(location_names: List[str]):
|
||||
@@ -325,21 +334,21 @@ class PokemonEmeraldWorld(World):
|
||||
# Filter progression items which shouldn't be shuffled into the itempool.
|
||||
# Their locations will still exist, but event items will be placed and
|
||||
# locked at their vanilla locations instead.
|
||||
filter_tags = set()
|
||||
filter_categories = set()
|
||||
|
||||
if not self.options.key_items:
|
||||
filter_tags.add("KeyItem")
|
||||
filter_categories.add(LocationCategory.KEY)
|
||||
if not self.options.rods:
|
||||
filter_tags.add("Rod")
|
||||
filter_categories.add(LocationCategory.ROD)
|
||||
if not self.options.bikes:
|
||||
filter_tags.add("Bike")
|
||||
filter_categories.add(LocationCategory.BIKE)
|
||||
if not self.options.event_tickets:
|
||||
filter_tags.add("EventTicket")
|
||||
filter_categories.add(LocationCategory.TICKET)
|
||||
|
||||
if self.options.badges in {RandomizeBadges.option_vanilla, RandomizeBadges.option_shuffle}:
|
||||
filter_tags.add("Badge")
|
||||
filter_categories.add(LocationCategory.BADGE)
|
||||
if self.options.hms in {RandomizeHms.option_vanilla, RandomizeHms.option_shuffle}:
|
||||
filter_tags.add("HM")
|
||||
filter_categories.add(LocationCategory.HM)
|
||||
|
||||
# If Badges and HMs are set to the `shuffle` option, don't add them to
|
||||
# the normal item pool, but do create their items and save them and
|
||||
@@ -347,17 +356,17 @@ class PokemonEmeraldWorld(World):
|
||||
if self.options.badges == RandomizeBadges.option_shuffle:
|
||||
self.badge_shuffle_info = [
|
||||
(location, self.create_item_by_code(location.default_item_code))
|
||||
for location in [l for l in item_locations if "Badge" in l.tags]
|
||||
for location in [l for l in item_locations if emerald_data.locations[l.key].category == LocationCategory.BADGE]
|
||||
]
|
||||
if self.options.hms == RandomizeHms.option_shuffle:
|
||||
self.hm_shuffle_info = [
|
||||
(location, self.create_item_by_code(location.default_item_code))
|
||||
for location in [l for l in item_locations if "HM" in l.tags]
|
||||
for location in [l for l in item_locations if emerald_data.locations[l.key].category == LocationCategory.HM]
|
||||
]
|
||||
|
||||
# Filter down locations to actual items that will be filled and create
|
||||
# the itempool.
|
||||
item_locations = [location for location in item_locations if len(filter_tags & location.tags) == 0]
|
||||
item_locations = [location for location in item_locations if emerald_data.locations[location.key].category not in filter_categories]
|
||||
default_itempool = [self.create_item_by_code(location.default_item_code) for location in item_locations]
|
||||
|
||||
# Take the itempool as-is
|
||||
@@ -366,7 +375,8 @@ class PokemonEmeraldWorld(World):
|
||||
|
||||
# Recreate the itempool from random items
|
||||
elif self.options.item_pool_type in (ItemPoolType.option_diverse, ItemPoolType.option_diverse_balanced):
|
||||
item_categories = ["Ball", "Heal", "Candy", "Vitamin", "EvoStone", "Money", "TM", "Held", "Misc", "Berry"]
|
||||
item_categories = ["Ball", "Healing", "Rare Candy", "Vitamin", "Evolution Stone",
|
||||
"Money", "TM", "Held", "Misc", "Berry"]
|
||||
|
||||
# Count occurrences of types of vanilla items in pool
|
||||
item_category_counter = Counter()
|
||||
@@ -436,25 +446,26 @@ class PokemonEmeraldWorld(World):
|
||||
|
||||
# Key items which are considered in access rules but not randomized are converted to events and placed
|
||||
# in their vanilla locations so that the player can have them in their inventory for logic.
|
||||
def convert_unrandomized_items_to_events(tag: str) -> None:
|
||||
def convert_unrandomized_items_to_events(category: LocationCategory) -> None:
|
||||
for location in self.multiworld.get_locations(self.player):
|
||||
if location.tags is not None and tag in location.tags:
|
||||
assert isinstance(location, PokemonEmeraldLocation)
|
||||
if location.key is not None and emerald_data.locations[location.key].category == category:
|
||||
location.place_locked_item(self.create_event(self.item_id_to_name[location.default_item_code]))
|
||||
location.progress_type = LocationProgressType.DEFAULT
|
||||
location.address = None
|
||||
|
||||
if self.options.badges == RandomizeBadges.option_vanilla:
|
||||
convert_unrandomized_items_to_events("Badge")
|
||||
convert_unrandomized_items_to_events(LocationCategory.BADGE)
|
||||
if self.options.hms == RandomizeHms.option_vanilla:
|
||||
convert_unrandomized_items_to_events("HM")
|
||||
convert_unrandomized_items_to_events(LocationCategory.HM)
|
||||
if not self.options.rods:
|
||||
convert_unrandomized_items_to_events("Rod")
|
||||
convert_unrandomized_items_to_events(LocationCategory.ROD)
|
||||
if not self.options.bikes:
|
||||
convert_unrandomized_items_to_events("Bike")
|
||||
convert_unrandomized_items_to_events(LocationCategory.BIKE)
|
||||
if not self.options.event_tickets:
|
||||
convert_unrandomized_items_to_events("EventTicket")
|
||||
convert_unrandomized_items_to_events(LocationCategory.TICKET)
|
||||
if not self.options.key_items:
|
||||
convert_unrandomized_items_to_events("KeyItem")
|
||||
convert_unrandomized_items_to_events(LocationCategory.KEY)
|
||||
|
||||
def pre_fill(self) -> None:
|
||||
# Badges and HMs that are set to shuffle need to be placed at
|
||||
|
||||
Reference in New Issue
Block a user