Pokémon Red and Blue: Version 4 update (#1963)
## What is this fixing or adding? Adds a large number of new options, including: - Door Shuffle - Sphere-based level scaling - Key Item and Pokedex requirement options to reach the Elite Four - Split Card Key option - Dexsanity option can be set to a percentage of Pokémon that will be checks - Stonesanity: remove the stones from the Celadon Department Store and shuffle them into the item pool, replacing 4 of the 5 Moon Stone items - Sleep Trap items option - Randomize Move Types option - Town Map Fly Location option, to unlock a flight location when finding/receiving the Town Map Many enhancements have been made, including: - Game allows you to continue your save file _from Pallet Town_ as a way to save warp back to the beginning of the game. The one-way drop from Diglett's Cave to north Route 2 that had been added to the randomizer has been removed. - Client auto-hints some locations when you are able to see the item before you can obtain it (but would only show AP Item if it is for another player), including Bike Shop, Oak's Aides, Celadon Prize Corner, and the unchosen Fossil location. Various bugs have been fixed, including: - Route 13 wild Pokémon not correctly logically requiring Cut - Vanilla tm/hm compatibility options giving compatibility for many TMs/HMs erroneously - If an item that exists in multiple quantities in the item pool is chosen for one of the locations that are pre-filled with local items, it will continue placing that same item in the remaining locations as long as more of that item exist - `start_with` option for `randomize_pokedex` still shuffling a Pokédex into the item pool - The obedience threshold levels being incorrect with 0-2 badges, with Pokémon up to level 30 obeying with 0-1 badges and up to 10 with 2 badges - Receiving a DeathLink trigger in the Safari Zone causing issues. Now, you will have your steps remaining set to 0 instead of blacking out when you're in the Safari Zone. Many location names have been changed, as location names are automatically prepended using the Region name and a large number of areas have been split into new regions as part of the overhaul to add Door Shuffle.
This commit is contained in:
@@ -1,86 +1,121 @@
|
||||
from ..AutoWorld import LogicMixin
|
||||
import worlds.pokemon_rb.poke_data as poke_data
|
||||
from . import poke_data
|
||||
|
||||
|
||||
class PokemonLogic(LogicMixin):
|
||||
def pokemon_rb_can_surf(self, player):
|
||||
return (((self.has("HM03 Surf", player) and self.can_learn_hm("10000", player))
|
||||
or self.has("Flippers", player)) and (self.has("Soul Badge", player) or
|
||||
self.has(self.multiworld.worlds[player].extra_badges.get("Surf"), player)
|
||||
or self.multiworld.badges_needed_for_hm_moves[player].value == 0))
|
||||
def can_surf(state, player):
|
||||
return (((state.has("HM03 Surf", player) and can_learn_hm(state, "Surf", player))
|
||||
or state.has("Flippers", player)) and (state.has("Soul Badge", player) or
|
||||
state.has(state.multiworld.worlds[player].extra_badges.get("Surf"), player)
|
||||
or state.multiworld.badges_needed_for_hm_moves[player].value == 0))
|
||||
|
||||
def pokemon_rb_can_cut(self, player):
|
||||
return ((self.has("HM01 Cut", player) and self.can_learn_hm("100", player) or self.has("Master Sword", player))
|
||||
and (self.has("Cascade Badge", player) or
|
||||
self.has(self.multiworld.worlds[player].extra_badges.get("Cut"), player) or
|
||||
self.multiworld.badges_needed_for_hm_moves[player].value == 0))
|
||||
|
||||
def pokemon_rb_can_fly(self, player):
|
||||
return (((self.has("HM02 Fly", player) and self.can_learn_hm("1000", player)) or self.has("Flute", player)) and
|
||||
(self.has("Thunder Badge", player) or self.has(self.multiworld.worlds[player].extra_badges.get("Fly"), player)
|
||||
or self.multiworld.badges_needed_for_hm_moves[player].value == 0))
|
||||
def can_cut(state, player):
|
||||
return ((state.has("HM01 Cut", player) and can_learn_hm(state, "Cut", player) or state.has("Master Sword", player))
|
||||
and (state.has("Cascade Badge", player) or
|
||||
state.has(state.multiworld.worlds[player].extra_badges.get("Cut"), player) or
|
||||
state.multiworld.badges_needed_for_hm_moves[player].value == 0))
|
||||
|
||||
def pokemon_rb_can_strength(self, player):
|
||||
return ((self.has("HM04 Strength", player) and self.can_learn_hm("100000", player)) or
|
||||
self.has("Titan's Mitt", player)) and (self.has("Rainbow Badge", player) or
|
||||
self.has(self.multiworld.worlds[player].extra_badges.get("Strength"), player)
|
||||
or self.multiworld.badges_needed_for_hm_moves[player].value == 0)
|
||||
|
||||
def pokemon_rb_can_flash(self, player):
|
||||
return (((self.has("HM05 Flash", player) and self.can_learn_hm("1000000", player)) or self.has("Lamp", player))
|
||||
and (self.has("Boulder Badge", player) or self.has(self.multiworld.worlds[player].extra_badges.get("Flash"),
|
||||
player) or self.multiworld.badges_needed_for_hm_moves[player].value == 0))
|
||||
def can_fly(state, player):
|
||||
return (((state.has("HM02 Fly", player) and can_learn_hm(state, "Fly", player)) or state.has("Flute", player)) and
|
||||
(state.has("Thunder Badge", player) or state.has(state.multiworld.worlds[player].extra_badges.get("Fly"), player)
|
||||
or state.multiworld.badges_needed_for_hm_moves[player].value == 0))
|
||||
|
||||
def can_learn_hm(self, move, player):
|
||||
for pokemon, data in self.multiworld.worlds[player].local_poke_data.items():
|
||||
if self.has(pokemon, player) and data["tms"][6] & int(move, 2):
|
||||
return True
|
||||
return False
|
||||
|
||||
def pokemon_rb_can_get_hidden_items(self, player):
|
||||
return self.has("Item Finder", player) or not self.multiworld.require_item_finder[player].value
|
||||
def can_strength(state, player):
|
||||
return ((state.has("HM04 Strength", player) and can_learn_hm(state, "Strength", player)) or
|
||||
state.has("Titan's Mitt", player)) and (state.has("Rainbow Badge", player) or
|
||||
state.has(state.multiworld.worlds[player].extra_badges.get("Strength"), player)
|
||||
or state.multiworld.badges_needed_for_hm_moves[player].value == 0)
|
||||
|
||||
def pokemon_rb_cerulean_cave(self, count, player):
|
||||
return len([item for item in
|
||||
["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Soul Badge", "Marsh Badge",
|
||||
"Volcano Badge", "Earth Badge", "Bicycle", "Silph Scope", "Item Finder", "Super Rod", "Good Rod",
|
||||
"Old Rod", "Lift Key", "Card Key", "Town Map", "Coin Case", "S.S. Ticket", "Secret Key",
|
||||
"Poke Flute", "Mansion Key", "Safari Pass", "Plant Key", "Hideout Key", "HM01 Cut", "HM02 Fly",
|
||||
"HM03 Surf", "HM04 Strength", "HM05 Flash"] if self.has(item, player)]) >= count
|
||||
|
||||
def pokemon_rb_can_pass_guards(self, player):
|
||||
if self.multiworld.tea[player].value:
|
||||
return self.has("Tea", player)
|
||||
else:
|
||||
return self.can_reach("Celadon City - Counter Man", "Location", player)
|
||||
def can_flash(state, player):
|
||||
return (((state.has("HM05 Flash", player) and can_learn_hm(state, "Flash", player)) or state.has("Lamp", player))
|
||||
and (state.has("Boulder Badge", player) or state.has(state.multiworld.worlds[player].extra_badges.get("Flash"),
|
||||
player) or state.multiworld.badges_needed_for_hm_moves[player].value == 0))
|
||||
|
||||
def pokemon_rb_has_badges(self, count, player):
|
||||
return len([item for item in ["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Marsh Badge",
|
||||
"Soul Badge", "Volcano Badge", "Earth Badge"] if self.has(item, player)]) >= count
|
||||
|
||||
def pokemon_rb_oaks_aide(self, count, player):
|
||||
return ((not self.multiworld.require_pokedex[player] or self.has("Pokedex", player))
|
||||
and self.pokemon_rb_has_pokemon(count, player))
|
||||
def can_learn_hm(state, move, player):
|
||||
for pokemon, data in state.multiworld.worlds[player].local_poke_data.items():
|
||||
if state.has(pokemon, player) and data["tms"][6] & 1 << (["Cut", "Fly", "Surf", "Strength",
|
||||
"Flash"].index(move) + 2):
|
||||
return True
|
||||
return False
|
||||
|
||||
def pokemon_rb_has_pokemon(self, count, player):
|
||||
obtained_pokemon = set()
|
||||
for pokemon in poke_data.pokemon_data.keys():
|
||||
if self.has(pokemon, player) or self.has(f"Static {pokemon}", player):
|
||||
obtained_pokemon.add(pokemon)
|
||||
|
||||
return len(obtained_pokemon) >= count
|
||||
def can_get_hidden_items(state, player):
|
||||
return state.has("Item Finder", player) or not state.multiworld.require_item_finder[player].value
|
||||
|
||||
def pokemon_rb_fossil_checks(self, count, player):
|
||||
return (self.can_reach('Mt Moon 1F - Southwest Item', 'Location', player) and
|
||||
self.can_reach('Cinnabar Island - Lab Scientist', 'Location', player) and len(
|
||||
[item for item in ["Dome Fossil", "Helix Fossil", "Old Amber"] if self.has(item, player)]) >= count)
|
||||
|
||||
def pokemon_rb_cinnabar_gym(self, player):
|
||||
# ensures higher level Pokémon are obtainable before Cinnabar Gym is in logic
|
||||
return ((self.multiworld.old_man[player] != "vanilla") or (not self.multiworld.extra_key_items[player]) or
|
||||
self.has("Mansion Key", player) or self.has("Oak's Parcel", player) or self.pokemon_rb_can_surf(player))
|
||||
def has_key_items(state, count, player):
|
||||
key_items = (len([item for item in ["Bicycle", "Silph Scope", "Item Finder", "Super Rod", "Good Rod",
|
||||
"Old Rod", "Lift Key", "Card Key", "Town Map", "Coin Case", "S.S. Ticket",
|
||||
"Secret Key", "Poke Flute", "Mansion Key", "Safari Pass", "Plant Key",
|
||||
"Hideout Key", "Card Key 2F", "Card Key 3F", "Card Key 4F", "Card Key 5F",
|
||||
"Card Key 6F", "Card Key 7F", "Card Key 8F", "Card Key 9F", "Card Key 10F",
|
||||
"Card Key 11F", "Exp. All", "Fire Stone", "Thunder Stone", "Water Stone",
|
||||
"Leaf Stone"] if state.has(item, player)])
|
||||
+ min(state.count("Progressive Card Key", player), 10))
|
||||
return key_items >= count
|
||||
|
||||
def pokemon_rb_dojo(self, player):
|
||||
# ensures higher level Pokémon are obtainable before Fighting Dojo is in logic
|
||||
return (self.pokemon_rb_can_pass_guards(player) or self.has("Oak's Parcel", player) or
|
||||
self.pokemon_rb_can_surf(player))
|
||||
|
||||
def can_pass_guards(state, player):
|
||||
if state.multiworld.tea[player]:
|
||||
return state.has("Tea", player)
|
||||
else:
|
||||
return state.has("Vending Machine Drinks", player)
|
||||
|
||||
|
||||
def has_badges(state, count, player):
|
||||
return len([item for item in ["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Marsh Badge",
|
||||
"Soul Badge", "Volcano Badge", "Earth Badge"] if state.has(item, player)]) >= count
|
||||
|
||||
|
||||
def oaks_aide(state, count, player):
|
||||
return ((not state.multiworld.require_pokedex[player] or state.has("Pokedex", player))
|
||||
and has_pokemon(state, count, player))
|
||||
|
||||
|
||||
def has_pokemon(state, count, player):
|
||||
obtained_pokemon = set()
|
||||
for pokemon in poke_data.pokemon_data.keys():
|
||||
if state.has(pokemon, player) or state.has(f"Static {pokemon}", player):
|
||||
obtained_pokemon.add(pokemon)
|
||||
|
||||
return len(obtained_pokemon) >= count
|
||||
|
||||
|
||||
def fossil_checks(state, count, player):
|
||||
return (state.can_reach('Mt Moon B2F', 'Region', player) and
|
||||
state.can_reach('Cinnabar Lab Fossil Room', 'Region', player) and
|
||||
state.can_reach('Cinnabar Island', 'Region', player) and len(
|
||||
[item for item in ["Dome Fossil", "Helix Fossil", "Old Amber"] if state.has(item, player)]) >= count)
|
||||
|
||||
|
||||
def card_key(state, floor, player):
|
||||
return state.has(f"Card Key {floor}F", player) or state.has("Card Key", player) or \
|
||||
state.has("Progressive Card Key", player, floor - 1)
|
||||
|
||||
|
||||
def rock_tunnel(state, player):
|
||||
return can_flash(state, player) or not state.multiworld.dark_rock_tunnel_logic[player]
|
||||
|
||||
|
||||
def route_3(state, player):
|
||||
if state.multiworld.route_3_condition[player] == "defeat_brock":
|
||||
return state.has("Defeat Brock", player)
|
||||
elif state.multiworld.route_3_condition[player] == "defeat_any_gym":
|
||||
return state.has_any(["Defeat Brock", "Defeat Misty", "Defeat Lt. Surge", "Defeat Erika", "Defeat Koga",
|
||||
"Defeat Blaine", "Defeat Sabrina", "Defeat Viridian Gym Giovanni"], player)
|
||||
elif state.multiworld.route_3_condition[player] == "boulder_badge":
|
||||
return state.has("Boulder Badge", player)
|
||||
elif state.multiworld.route_3_condition[player] == "any_badge":
|
||||
return state.has_any(["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Marsh Badge",
|
||||
"Soul Badge", "Volcano Badge", "Earth Badge"], player)
|
||||
# open
|
||||
return True
|
||||
|
||||
|
||||
def evolve_level(state, level, player):
|
||||
return len([item for item in (
|
||||
"Defeat Brock", "Defeat Misty", "Defeat Lt. Surge", "Defeat Erika", "Defeat Koga", "Defeat Blaine",
|
||||
"Defeat Sabrina", "Defeat Viridian Gym Giovanni") if state.has(item, player)]) > level / 7
|
||||
|
||||
Reference in New Issue
Block a user