mirror of
https://github.com/veekun/pokedex.git
synced 2024-08-20 18:16:34 +00:00
Implement form switching and Rotom's form moves
This commit is contained in:
parent
850c63c32e
commit
a765f95eda
1 changed files with 53 additions and 5 deletions
|
@ -279,6 +279,19 @@ class MovesetSearch(object):
|
||||||
cost = costs['tutor-once']
|
cost = costs['tutor-once']
|
||||||
elif method == 'egg':
|
elif method == 'egg':
|
||||||
cost = costs['breed']
|
cost = costs['breed']
|
||||||
|
elif method == 'form-change':
|
||||||
|
cost = costs[method]
|
||||||
|
# XXX: Ugly
|
||||||
|
# Prevent Rotom from breeding.
|
||||||
|
# Since it's genderless and doesn't evolve, breeding
|
||||||
|
# would be unnecessary. The normal algorithm would
|
||||||
|
# give its form-change move to the baby Rotom, though,
|
||||||
|
# which would allow it to learn another one... aaaaa
|
||||||
|
# The alternative is checking moves for 'form-change'
|
||||||
|
# on every breed, or making form-change entirely
|
||||||
|
# separate :(
|
||||||
|
self.unbreedable = self.unbreedable.union(
|
||||||
|
self.switchable_form_pokemon[pokemon])
|
||||||
else:
|
else:
|
||||||
cost = costs[method]
|
cost = costs[method]
|
||||||
movepools[chain][move] = min(
|
movepools[chain][move] = min(
|
||||||
|
@ -322,6 +335,7 @@ class MovesetSearch(object):
|
||||||
self.babies[egg_group_id] = set of baby pokemon
|
self.babies[egg_group_id] = set of baby pokemon
|
||||||
self.hatch_counters[pokemon] = hatch counter
|
self.hatch_counters[pokemon] = hatch counter
|
||||||
self.gender_rates[evolution_chain] = gender rate
|
self.gender_rates[evolution_chain] = gender rate
|
||||||
|
self.switchable_form_pokemon[pokemon] = set of pokemon for switchable forms
|
||||||
"""
|
"""
|
||||||
eg1 = tables.PokemonEggGroup
|
eg1 = tables.PokemonEggGroup
|
||||||
eg2 = aliased(tables.PokemonEggGroup)
|
eg2 = aliased(tables.PokemonEggGroup)
|
||||||
|
@ -331,6 +345,8 @@ class MovesetSearch(object):
|
||||||
query = self.session.query(
|
query = self.session.query(
|
||||||
tables.Pokemon.id,
|
tables.Pokemon.id,
|
||||||
tables.PokemonSpecies.evolution_chain_id,
|
tables.PokemonSpecies.evolution_chain_id,
|
||||||
|
tables.PokemonSpecies.id,
|
||||||
|
tables.PokemonSpecies.forms_switchable,
|
||||||
parent_pokemon.id,
|
parent_pokemon.id,
|
||||||
eg1.egg_group_id,
|
eg1.egg_group_id,
|
||||||
eg2.egg_group_id,
|
eg2.egg_group_id,
|
||||||
|
@ -356,8 +372,11 @@ class MovesetSearch(object):
|
||||||
self.babies = defaultdict(set)
|
self.babies = defaultdict(set)
|
||||||
self.hatch_counters = dict()
|
self.hatch_counters = dict()
|
||||||
self.gender_rates = dict()
|
self.gender_rates = dict()
|
||||||
|
self.switchable_form_pokemon = dict()
|
||||||
|
switchable_pokemon_by_species = defaultdict(set)
|
||||||
item_baby_chains = set() # evolution chains with baby-trigger items
|
item_baby_chains = set() # evolution chains with baby-trigger items
|
||||||
for pokemon, evolution_chain, parent, g1, g2, baby_item, hatch_counter, gender_rate in query:
|
for (pokemon, evolution_chain, species, forms_switchable, parent,
|
||||||
|
g1, g2, baby_item, hatch_counter, gender_rate) in query:
|
||||||
self.hatch_counters[pokemon] = hatch_counter
|
self.hatch_counters[pokemon] = hatch_counter
|
||||||
self.gender_rates[evolution_chain] = gender_rate
|
self.gender_rates[evolution_chain] = gender_rate
|
||||||
if g1 in bad_groups:
|
if g1 in bad_groups:
|
||||||
|
@ -374,6 +393,15 @@ class MovesetSearch(object):
|
||||||
self.evolution_parents[pokemon] = parent
|
self.evolution_parents[pokemon] = parent
|
||||||
if baby_item:
|
if baby_item:
|
||||||
item_baby_chains.add(evolution_chain)
|
item_baby_chains.add(evolution_chain)
|
||||||
|
if forms_switchable:
|
||||||
|
# Each form-swithable species shares a set of the switchable
|
||||||
|
# pokemon. When adding a pokémon we assign the set to it,
|
||||||
|
# and add the pokémon to it (mutating the shared copy).
|
||||||
|
# So in the end, each of the pokémon ends up with the complete
|
||||||
|
# set for its species.
|
||||||
|
switchable = switchable_pokemon_by_species[species]
|
||||||
|
self.switchable_form_pokemon[pokemon] = switchable
|
||||||
|
switchable.add(pokemon)
|
||||||
self.unbreedable = frozenset(unbreedable)
|
self.unbreedable = frozenset(unbreedable)
|
||||||
|
|
||||||
self.evolutions = defaultdict(set)
|
self.evolutions = defaultdict(set)
|
||||||
|
@ -642,6 +670,7 @@ default_costs = {
|
||||||
'forget': 300, # Deleting a move. (Not needed unless deleting an evolution move.)
|
'forget': 300, # Deleting a move. (Not needed unless deleting an evolution move.)
|
||||||
'relearn': 150, # Also a pain, though not as big as breeding.
|
'relearn': 150, # Also a pain, though not as big as breeding.
|
||||||
'per-level': 1, # Prefer less grinding. This is for all lv-ups but the final “grow”
|
'per-level': 1, # Prefer less grinding. This is for all lv-ups but the final “grow”
|
||||||
|
'form-switch': 5, # Not a big deal
|
||||||
|
|
||||||
# Breeding for moves the target pokemon leans easily is kind of stupid.
|
# Breeding for moves the target pokemon leans easily is kind of stupid.
|
||||||
# (Though not *very* stupid, and since the program considers evolution
|
# (Though not *very* stupid, and since the program considers evolution
|
||||||
|
@ -941,6 +970,10 @@ class ShedEvolutionAction(EvolutionAction, namedtuple('EvolutionAction', 'search
|
||||||
mvs = ', '.join(m.name for m in self.moves)
|
mvs = ', '.join(m.name for m in self.moves)
|
||||||
return u"Co-evolve to {0.pokemon.name}, learning {1}".format(self, mvs)
|
return u"Co-evolve to {0.pokemon.name}, learning {1}".format(self, mvs)
|
||||||
|
|
||||||
|
class FormSwitchAction(Action, namedtuple('EvolutionAction', 'search pokemon_')):
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"Switch to {0.pokemon.name}".format(self)
|
||||||
|
|
||||||
class GrowAction(Action, namedtuple('GrowAction', 'search level')):
|
class GrowAction(Action, namedtuple('GrowAction', 'search level')):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Grow to level {0.level}".format(self)
|
return u"Grow to level {0.level}".format(self)
|
||||||
|
@ -1039,6 +1072,7 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
|
||||||
self.expand_trade(),
|
self.expand_trade(),
|
||||||
self.expand_grow(),
|
self.expand_grow(),
|
||||||
self.expand_evolutions(),
|
self.expand_evolutions(),
|
||||||
|
self.expand_form_change(),
|
||||||
self.expand_breed(),
|
self.expand_breed(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1076,8 +1110,15 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
|
||||||
for level, cost in levels_costs:
|
for level, cost in levels_costs:
|
||||||
yield self._learn(move, method, cost, new_level=False)
|
yield self._learn(move, method, cost, new_level=False)
|
||||||
elif method == 'form-change':
|
elif method == 'form-change':
|
||||||
# XXX: Form changes
|
for level, cost in levels_costs:
|
||||||
pass
|
# Learn this at level 100, but only if the current
|
||||||
|
# level is strictly lower.
|
||||||
|
# That'll prevent the pokémon to learn more than one
|
||||||
|
# of these without us having to keep track of the other
|
||||||
|
# forms and their moves.
|
||||||
|
if self.level < 100:
|
||||||
|
yield self._learn(move, method, cost,
|
||||||
|
level=100, new_level=True)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown move method %s' % method)
|
raise ValueError('Unknown move method %s' % method)
|
||||||
|
|
||||||
|
@ -1117,7 +1158,7 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
|
||||||
self.level <= search.goal_level):
|
self.level <= search.goal_level):
|
||||||
kwargs = self._asdict()
|
kwargs = self._asdict()
|
||||||
kwargs['level'] = search.goal_level
|
kwargs['level'] = search.goal_level
|
||||||
kwargs['new_level'] = True
|
kwargs['new_level'] = 'G'
|
||||||
yield 0, GrowAction(search, search.goal_level), GoalNode(**kwargs)
|
yield 0, GrowAction(search, search.goal_level), GoalNode(**kwargs)
|
||||||
|
|
||||||
def expand_evolutions(self):
|
def expand_evolutions(self):
|
||||||
|
@ -1181,6 +1222,13 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
|
||||||
yield cost, EvolutionAction(search, child, trigger, self.moves_), self._replace(
|
yield cost, EvolutionAction(search, child, trigger, self.moves_), self._replace(
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
|
def expand_form_change(self):
|
||||||
|
search = self.search
|
||||||
|
for pokemon in search.switchable_form_pokemon.get(self.pokemon_, ()):
|
||||||
|
if pokemon != self.pokemon_:
|
||||||
|
yield search.costs['form-switch'], FormSwitchAction(
|
||||||
|
search, pokemon), self._replace(pokemon_=pokemon, new_level=False)
|
||||||
|
|
||||||
def expand_breed(self):
|
def expand_breed(self):
|
||||||
search = self.search
|
search = self.search
|
||||||
if self.pokemon_ in search.unbreedable:
|
if self.pokemon_ in search.unbreedable:
|
||||||
|
@ -1197,7 +1245,7 @@ class PokemonNode(Node, Facade, namedtuple('PokemonNode',
|
||||||
goal_groups = search.egg_groups[goal_family]
|
goal_groups = search.egg_groups[goal_family]
|
||||||
goal_compatible = set(goal_groups).intersection(egg_groups)
|
goal_compatible = set(goal_groups).intersection(egg_groups)
|
||||||
if 0 < gender_rate:
|
if 0 < gender_rate:
|
||||||
# Only pokemon that have males can pas down moves to other species
|
# Only pokemon that have males can pass down moves to other species
|
||||||
# (and the other species must have females: checked in BreedNode)
|
# (and the other species must have females: checked in BreedNode)
|
||||||
for group in egg_groups:
|
for group in egg_groups:
|
||||||
if moves in breeds_required[group]:
|
if moves in breeds_required[group]:
|
||||||
|
|
Loading…
Reference in a new issue