Split tables.py into several files

Also, remove the test alphabetical order
This commit is contained in:
Petr Viktorin 2014-12-29 14:57:01 +01:00
parent 339181032f
commit 981851420e
5 changed files with 697 additions and 652 deletions

View file

@ -0,0 +1,61 @@
# encoding: utf8
u"""The Pokédex schema.
Columns have a info dictionary with these keys:
- official: True if the values appear in games or official material; False if
they are fan-created or fan-written. This flag is currently only set for
official text columns.
- format: The format of a text column. Can be one of:
- plaintext: Normal Unicode text (widely used in names)
- markdown: Veekun's Markdown flavor (generally used in effect descriptions)
- gametext: Transcription of in-game text that strives to be both
human-readable and represent the original text exactly.
- identifier: A fan-made identifier in the [-_a-z0-9]* format. Not intended
for translation.
- latex: A formula in LaTeX syntax.
- ripped: True for text that has been ripped from the games, and can be ripped
again for new versions or languages
- string_getter: for translation columns, a function taking (text, session,
language) that is used for properties on the main table. Used for Markdown
text.
See `pokedex.db.multilang` for how localizable text columns work. The session
classes in that module can be used to change the default language.
"""
from pokedex.db.tables.base import (
metadata, TableBase, mapped_classes, Language, create_translation_table)
from pokedex.db.tables.core import (
Ability, AbilityChangelog, AbilityFlavorText, Berry, BerryFirmness,
BerryFlavor, Characteristic, ContestCombo, ContestEffect, ContestType,
EggGroup, Encounter, EncounterCondition, EncounterConditionValue,
EncounterConditionValueMap, EncounterMethod, EncounterSlot, EvolutionChain,
EvolutionTrigger, Experience, Gender, Generation, GrowthRate, Item,
ItemCategory, ItemFlag, ItemFlagMap, ItemFlavorText, ItemFlingEffect,
ItemGameIndex, ItemPocket, Location, LocationArea,
LocationAreaEncounterRate, LocationGameIndex, Machine, Move,
MoveBattleStyle, MoveChangelog, MoveDamageClass, MoveEffect,
MoveEffectChangelog, MoveFlag, MoveFlagMap, MoveFlavorText, MoveMeta,
MoveMetaAilment, MoveMetaCategory, MoveMetaStatChange, MoveTarget, Nature,
NatureBattleStylePreference, NaturePokeathlonStat, PalPark, PalParkArea,
PokeathlonStat, Pokedex, PokedexVersionGroup, Pokemon, PokemonAbility,
PokemonColor, PokemonDexNumber, PokemonEggGroup, PokemonEvolution,
PokemonForm, PokemonFormGeneration, PokemonFormPokeathlonStat,
PokemonGameIndex, PokemonHabitat, PokemonItem, PokemonMove,
PokemonMoveMethod, PokemonShape, PokemonSpecies, PokemonSpeciesFlavorText,
PokemonStat, PokemonType, Region, Stat, SuperContestCombo,
SuperContestEffect, Type, TypeEfficacy, TypeGameIndex, Version,
VersionGroup, VersionGroupPokemonMoveMethod, VersionGroupRegion)
from pokedex.db.tables.conquest import (
ConquestEpisode, ConquestEpisodeWarrior, ConquestKingdom, ConquestMaxLink,
ConquestMoveData, ConquestMoveDisplacement, ConquestMoveEffect,
ConquestMoveRange, ConquestPokemonAbility, ConquestPokemonEvolution,
ConquestPokemonMove, ConquestPokemonStat, ConquestStat,
ConquestTransformationPokemon, ConquestTransformationWarrior,
ConquestWarrior, ConquestWarriorArchetype, ConquestWarriorRank,
ConquestWarriorRankStatMap, ConquestWarriorSkill, ConquestWarriorSpecialty,
ConquestWarriorStat, ConquestWarriorTransformation)

80
pokedex/db/tables/base.py Normal file
View file

@ -0,0 +1,80 @@
# encoding: utf8
from functools import partial
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
from sqlalchemy import Column, MetaData
from sqlalchemy.types import Boolean, Integer, Unicode
from pokedex.db import multilang
class TableSuperclass(object):
"""Superclass for declarative tables, to give them some generic niceties
like stringification.
"""
def __unicode__(self):
"""Be as useful as possible. Show the primary key, and an identifier
if we've got one.
"""
typename = u'.'.join((__name__, type(self).__name__))
pk_constraint = self.__table__.primary_key
if not pk_constraint:
return u"<%s object at %x>" % (typename, id(self))
pk = u', '.join(unicode(getattr(self, column.name))
for column in pk_constraint.columns)
try:
return u"<%s object (%s): %s>" % (typename, pk, self.identifier)
except AttributeError:
return u"<%s object (%s)>" % (typename, pk)
def __str__(self):
return unicode(self).encode('utf8')
def __repr__(self):
return unicode(self).encode('utf8')
mapped_classes = []
class TableMetaclass(DeclarativeMeta):
def __init__(cls, name, bases, attrs):
super(TableMetaclass, cls).__init__(name, bases, attrs)
if hasattr(cls, '__tablename__'):
mapped_classes.append(cls)
cls.translation_classes = []
metadata = MetaData()
TableBase = declarative_base(metadata=metadata, cls=TableSuperclass, metaclass=TableMetaclass)
### Need Language first, to create the partial() below
class Language(TableBase):
u"""A language the Pokémon games have been translated into."""
__tablename__ = 'languages'
__singlename__ = 'language'
id = Column(Integer, primary_key=True, nullable=False,
doc=u"A numeric ID")
iso639 = Column(Unicode(79), nullable=False,
doc=u"The two-letter code of the country where this language is spoken. Note that it is not unique.",
info=dict(format='identifier'))
iso3166 = Column(Unicode(79), nullable=False,
doc=u"The two-letter code of the language. Note that it is not unique.",
info=dict(format='identifier'))
identifier = Column(Unicode(79), nullable=False,
doc=u"An identifier",
info=dict(format='identifier'))
official = Column(Boolean, nullable=False, index=True,
doc=u"True iff games are produced in the language.")
order = Column(Integer, nullable=True,
doc=u"Order for sorting in foreign name lists.")
create_translation_table = partial(multilang.create_translation_table, language_class=Language)
create_translation_table('language_names', Language, 'names',
name = Column(Unicode(79), nullable=False, index=True,
doc=u"The name",
info=dict(format='plaintext', official=True)),
)

View file

@ -0,0 +1,550 @@
# encoding: utf8
from sqlalchemy import Column, ForeignKey, UniqueConstraint
from sqlalchemy.orm import backref, relationship
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.types import Boolean, Integer, Unicode, UnicodeText
from pokedex.db.tables.base import TableBase, create_translation_table
from pokedex.db.tables.core import (
Move, Type, Ability, PokemonSpecies, Gender, Item)
from pokedex.db import markdown
class ConquestEpisode(TableBase):
u"""An episode from Pokémon Conquest: one of a bunch of mini-stories
featuring a particular warrior.
The main story, "The Legend of Ransei", also counts, even though it's not
in the episode select menu and there's no way to replay it.
"""
__tablename__ = 'conquest_episodes'
__singlename__ = 'episode'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this episode.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this episode.',
info=dict(format='identifier'))
create_translation_table('conquest_episode_names', ConquestEpisode, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestEpisodeWarrior(TableBase):
u"""A warrior featured in an episode in Pokémon Conquest.
This needs its own table because of the player having two episodes and
there being two players.
"""
__tablename__ = 'conquest_episode_warriors'
episode_id = Column(Integer, ForeignKey('conquest_episodes.id'), primary_key=True,
doc=u'The ID of the episode.')
warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), primary_key=True,
doc=u'The ID of the warrior.')
class ConquestKingdom(TableBase):
u"""A kingdom in Pokémon Conquest."""
__tablename__ = 'conquest_kingdoms'
__singlename__ = 'kingdom'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u"An ID for this kingdom.")
identifier = Column(Unicode(79), nullable=False,
doc=u"A readable identifier for this kingdom.",
info=dict(format='identifier'))
type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
doc=u"The type associated with this kingdom in-game.")
create_translation_table('conquest_kingdom_names', ConquestKingdom, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestMaxLink(TableBase):
u"""The maximum link a warrior rank can reach with a Pokémon in Pokémon Conquest."""
__tablename__ = 'conquest_max_links'
warrior_rank_id = Column(Integer, ForeignKey('conquest_warrior_ranks.id'), primary_key=True,
doc=u"The ID of the warrior rank.")
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True,
doc=u'The ID of the Pokémon species.')
max_link = Column(Integer, nullable=False,
doc=u'The maximum link percentage this warrior rank and Pokémon can reach.')
class ConquestMoveData(TableBase):
u"""Data about a move in Pokémon Conquest."""
__tablename__ = 'conquest_move_data'
move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the move.')
power = Column(Integer, nullable=True,
doc=u"The move's power, null if it does no damage.")
accuracy = Column(Integer, nullable=True,
doc=u"The move's base accuracy, null if it is self-targeted or never misses.")
effect_chance = Column(Integer, nullable=True,
doc=u"The chance as a percentage that the move's secondary effect will trigger.")
effect_id = Column(Integer, ForeignKey('conquest_move_effects.id'), nullable=False,
doc=u"The ID of the move's effect.")
range_id = Column(Integer, ForeignKey('conquest_move_ranges.id'), nullable=False,
doc=u"The ID of the move's range.")
displacement_id = Column(Integer, ForeignKey('conquest_move_displacements.id'), nullable=True,
doc=u"The ID of the move's displacement.")
@property
def star_rating(self):
"""Return the move's in-game power rating as a number of stars."""
if not self.power:
return 0
else:
stars = (self.power - 1) // 10
stars = min(stars, 5) # i.e. maximum of 5 stars
stars = max(stars, 1) # And minimum of 1
return stars
class ConquestMoveDisplacement(TableBase):
u"""A way in which a move can cause the user or target to move to a
different tile.
If a move displaces its user, the move's range is relative to the user's
original position.
"""
__tablename__ = 'conquest_move_displacements'
__singlename__ = 'move_displacement'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this displacement.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this displacement.',
info=dict(format='identifier'))
affects_target = Column(Boolean, nullable=False,
doc=u'True iff the move displaces its target(s) and not its user.')
create_translation_table('conquest_move_displacement_prose', ConquestMoveDisplacement, 'prose',
name = Column(Unicode(79), nullable=True,
doc=u'A name for the displacement.',
info=dict(format='plaintext')),
short_effect = Column(UnicodeText, nullable=True,
doc=u"A short summary of how the displacement works, to be used in the move's short effect.",
info=dict(format='markdown')),
effect = Column(UnicodeText, nullable=True,
doc=u"A detailed description of how the displacement works, to be used alongside the move's long effect.",
info=dict(format='markdown')),
)
class ConquestMoveEffect(TableBase):
u"""An effect moves can have in Pokémon Conquest."""
__tablename__ = 'conquest_move_effects'
__singlename__ = 'conquest_move_effect'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this effect.')
create_translation_table('conquest_move_effect_prose', ConquestMoveEffect, 'prose',
short_effect = Column(UnicodeText, nullable=True,
doc=u"A short summary of the effect",
info=dict(format='markdown')),
effect = Column(UnicodeText, nullable=True,
doc=u"A detailed description of the effect",
info=dict(format='markdown')),
)
class ConquestMoveRange(TableBase):
u"""A set of tiles moves can target in Pokémon Conquest."""
__tablename__ = 'conquest_move_ranges'
__singlename__ = 'conquest_move_range'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this range.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this range.',
info=dict(format='identifier'))
targets = Column(Integer, nullable=False,
doc=u'The number of tiles this range targets.')
create_translation_table('conquest_move_range_prose', ConquestMoveRange, 'prose',
name = Column(Unicode(79), nullable=True,
doc=u"A short name briefly describing the range",
info=dict(format='plaintext')),
description = Column(UnicodeText, nullable=True,
doc=u"A detailed description of the range",
info=dict(format='plaintext')),
)
class ConquestPokemonAbility(TableBase):
u"""An ability a Pokémon species has in Pokémon Conquest."""
__tablename__ = 'conquest_pokemon_abilities'
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True, nullable=False, autoincrement=False,
doc=u'The ID of the Pokémon species with this ability.')
slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
doc=u"The order abilities are listed in. Upon evolution, if a Pokémon's abilities change, it will receive the one in the same slot.")
ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
doc=u'The ID of the ability.')
class ConquestPokemonEvolution(TableBase):
u"""The conditions under which a Pokémon must successfully complete an
action to evolve in Pokémon Conquest.
Any condition may be null if it does not apply for a particular Pokémon.
"""
__tablename__ = 'conquest_pokemon_evolution'
evolved_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True, nullable=False,
doc=u"The ID of the post-evolution species.")
required_stat_id = Column(Integer, ForeignKey('conquest_stats.id'), nullable=True,
doc=u"The ID of the stat which minimum_stat applies to.")
minimum_stat = Column(Integer, nullable=True,
doc=u"The minimum value the Pokémon must have in a particular stat.")
minimum_link = Column(Integer, nullable=True,
doc=u"The minimum link percentage the Pokémon must have with its warrior.")
kingdom_id = Column(Integer, ForeignKey('conquest_kingdoms.id'), nullable=True,
doc=u"The ID of the kingdom in which this Pokémon must complete an action after meeting all other requirements.")
warrior_gender_id = Column(Integer, ForeignKey('genders.id'), nullable=True,
doc=u"The ID of the gender the Pokémon's warrior must be.")
item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
doc=u"The ID of the item the Pokémon's warrior must have equipped.")
recruiting_ko_required = Column(Boolean, nullable=False,
doc=u"If true, the Pokémon must KO a Pokémon under the right conditions to recruit that Pokémon's warrior.")
class ConquestPokemonMove(TableBase):
u"""A Pokémon's move in Pokémon Conquest.
Yes, "move"; each Pokémon has exactly one.
"""
__tablename__ = 'conquest_pokemon_moves'
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the Pokémon species.')
move_id = Column(Integer, ForeignKey('moves.id'), nullable=False,
doc=u'The ID of the move.')
class ConquestPokemonStat(TableBase):
u"""A Pokémon's base stat in Pokémon Conquest.
The main four base stats in Conquest are derived from level 100 stats in
the main series (ignoring effort, genes, and natures). Attack matches
either Attack or Special Attack, and Defense matches the average of Defense
and Special Defense. HP and Speed are the same.
"""
__tablename__ = 'conquest_pokemon_stats'
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the Pokémon species.')
conquest_stat_id = Column(Integer, ForeignKey('conquest_stats.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the stat.')
base_stat = Column(Integer, nullable=False,
doc=u'The base stat.')
class ConquestStat(TableBase):
u"""A stat Pokémon have in Pokémon Conquest."""
__tablename__ = 'conquest_stats'
__singlename__ = 'conquest_stat' # To be safe
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this stat.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this stat.',
info=dict(format='identifier'))
is_base = Column(Boolean, nullable=False,
doc=u'True iff this is one of the main stats, calculated for individual Pokémon.')
create_translation_table('conquest_stat_names', ConquestStat, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestTransformationPokemon(TableBase):
u"""A Pokémon that satisfies a warrior transformation's link condition.
If a warrior has one or more Pokémon listed here, they only need to raise
one of them to the required link.
"""
__tablename__ = 'conquest_transformation_pokemon'
transformation_id = Column(Integer, ForeignKey('conquest_warrior_transformation.transformed_warrior_rank_id'), primary_key=True,
doc=u'The ID of the corresponding transformation, in turn a warrior rank ID.')
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True,
doc=u'The ID of the Pokémon species.')
class ConquestTransformationWarrior(TableBase):
u"""A warrior who must be present in the same nation as another warrior for
the latter to transform into their next rank.
If a warrior has one or more other warriors listed here, they *all* need to
gather in the same nation for the transformation to take place.
"""
__tablename__ = 'conquest_transformation_warriors'
transformation_id = Column(Integer, ForeignKey('conquest_warrior_transformation.transformed_warrior_rank_id'), primary_key=True,
doc=u'The ID of the corresponding transformation, in turn a warrior rank ID.')
present_warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), primary_key=True,
doc=u'The ID of the other warrior who must be present.')
class ConquestWarrior(TableBase):
u"""A warrior in Pokémon Conquest."""
__tablename__ = 'conquest_warriors'
__singlename__ = 'warrior'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=True,
doc=u'An ID for this warrior.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this warrior.',
info=dict(format='identifier'))
gender_id = Column(Integer, ForeignKey('genders.id'), nullable=False,
doc=u"The ID of the warrior's gender.")
archetype_id = Column(Integer, ForeignKey('conquest_warrior_archetypes.id'), nullable=True,
doc=u"The ID of this warrior's archetype. Null for unique warriors.")
create_translation_table('conquest_warrior_names', ConquestWarrior, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestWarriorArchetype(TableBase):
u"""An archetype that generic warriors in Pokémon Conquest can have. All
warriors of a particular archetype share sprites and dialogue.
Some of these are unused as warriors because they exist only as NPCs. They
should still be kept because we have their sprites and may eventually get
their dialogue.
"""
__tablename__ = 'conquest_warrior_archetypes'
__singlename__ = 'archetype'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this archetype.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier describing this archetype.',
info=dict(format='identifier'))
class ConquestWarriorRank(TableBase):
u"""A warrior at a particular rank in Pokémon Conquest.
These are used for whatever changes between ranks, much like Pokémon forms.
Generic warriors who have only one rank are also represented here, with a
single row.
To clarify, each warrior's ranks are individually called "warrior ranks"
here; for example, "Rank 2 Nobunaga" is an example of a warrior rank, not
just "Rank 2".
"""
__tablename__ = 'conquest_warrior_ranks'
__singlename__ = 'warrior_rank'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this warrior rank.')
warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), nullable=False,
doc=u'The ID of the warrior.')
rank = Column(Integer, nullable=False,
doc=u'The rank number.')
skill_id = Column(Integer, ForeignKey('conquest_warrior_skills.id'), nullable=False,
doc=u"The ID of this warrior rank's warrior skill.")
__table_args__ = (
UniqueConstraint(warrior_id, rank),
{},
)
class ConquestWarriorRankStatMap(TableBase):
u"""Any of a warrior rank's warrior stats in Pokémon Conquest."""
__tablename__ = 'conquest_warrior_rank_stat_map'
warrior_rank_id = Column(Integer, ForeignKey('conquest_warrior_ranks.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the warrior rank.')
warrior_stat_id = Column(Integer, ForeignKey('conquest_warrior_stats.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the warrior stat.')
base_stat = Column(Integer, nullable=False,
doc=u'The stat.')
class ConquestWarriorSkill(TableBase):
u"""A warrior skill in Pokémon Conquest."""
__tablename__ = 'conquest_warrior_skills'
__singlename__ = 'skill'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=True,
doc=u'An ID for this skill.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this skill.',
info=dict(format='identifier'))
create_translation_table('conquest_warrior_skill_names', ConquestWarriorSkill, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestWarriorSpecialty(TableBase):
u"""A warrior's specialty types in Pokémon Conquest.
These have no actual effect on gameplay; they just indicate which types of
Pokémon each warrior generally has strong maximum links with.
"""
__tablename__ = 'conquest_warrior_specialties'
warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), primary_key=True, nullable=False, autoincrement=False,
doc=u'The ID of the warrior.')
type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
doc=u'The ID of the type.')
slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
doc=u"The order in which the warrior's types are listed.")
class ConquestWarriorStat(TableBase):
u"""A stat that warriors have in Pokémon Conquest."""
__tablename__ = 'conquest_warrior_stats'
__singlename__ = 'warrior_stat'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this stat.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this stat.',
info=dict(format='identifier'))
create_translation_table('conquest_warrior_stat_names', ConquestWarriorStat, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestWarriorTransformation(TableBase):
u"""The conditions under which a warrior must perform an action in order
to transform to the next rank.
Or most of them, anyway. See also ConquestTransformationPokemon and
ConquestTransformationWarrior.
"""
__tablename__ = 'conquest_warrior_transformation'
transformed_warrior_rank_id = Column(Integer, ForeignKey('conquest_warrior_ranks.id'), primary_key=True,
doc=u'The ID of the post-transformation warrior rank.')
is_automatic = Column(Boolean, nullable=False,
doc=u'True iff the transformation happens automatically in the story with no further requirements.')
required_link = Column(Integer, nullable=True,
doc=u'The link percentage the warrior must reach with one of several specific Pokémon, if any.')
completed_episode_id = Column(Integer, ForeignKey('conquest_episodes.id'), nullable=True,
doc=u'The ID of the episode the player must have completed, if any.')
current_episode_id = Column(Integer, ForeignKey('conquest_episodes.id'), nullable=True,
doc=u'The ID of the episode the player must currently be playing, if any.')
distant_warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), nullable=True,
doc=u'The ID of another warrior who must be in the army, but not in the same kingdom or in any adjacent kingdom.')
female_warlord_count = Column(Integer, nullable=True,
doc=u'The number of female warlords who must be in the same nation.')
pokemon_count = Column(Integer, nullable=True,
doc=u'The number of Pokémon that must be registered in the gallery.')
collection_type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
doc=u'The ID of a type all Pokémon of which must be registered in the gallery.')
warrior_count = Column(Integer, nullable=True,
doc=u'The number of warriors that must be registered in the gallery.')
### Relationships down here, to avoid dependency ordering problems
ConquestEpisode.warriors = relationship(ConquestWarrior,
secondary=ConquestEpisodeWarrior.__table__,
innerjoin=True,
backref='episodes')
ConquestKingdom.type = relationship(Type,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('conquest_kingdom', uselist=False))
ConquestMaxLink.pokemon = relationship(PokemonSpecies,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('conquest_max_links', lazy='dynamic',
order_by=ConquestMaxLink.warrior_rank_id))
ConquestMaxLink.warrior_rank = relationship(ConquestWarriorRank,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('max_links', lazy='dynamic'))
ConquestMaxLink.warrior = association_proxy('warrior_rank', 'warrior')
ConquestMoveData.move_displacement = relationship(ConquestMoveDisplacement,
uselist=False,
backref='move_data')
ConquestMoveData.move = relationship(Move,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('conquest_data', uselist=False))
ConquestMoveData.move_effect = relationship(ConquestMoveEffect,
innerjoin=True, lazy='joined',
backref='move_data')
ConquestMoveData.range = relationship(ConquestMoveRange,
innerjoin=True, lazy='joined',
backref='move_data')
ConquestMoveData.effect = markdown.MoveEffectProperty('effect')
ConquestMoveData.effect_map = markdown.MoveEffectPropertyMap('effect_map')
ConquestMoveData.short_effect = markdown.MoveEffectProperty('short_effect')
ConquestMoveData.short_effect_map = markdown.MoveEffectPropertyMap('short_effect_map')
ConquestMoveData.displacement = markdown.MoveEffectProperty('effect', relationship='move_displacement')
ConquestPokemonEvolution.gender = relationship(Gender,
backref='conquest_evolutions')
ConquestPokemonEvolution.item = relationship(Item,
backref='conquest_evolutions')
ConquestPokemonEvolution.kingdom = relationship(ConquestKingdom,
backref='evolutions')
ConquestPokemonEvolution.stat = relationship(ConquestStat,
backref='evolutions')
ConquestPokemonStat.pokemon = relationship(PokemonSpecies,
uselist=False,
innerjoin=True, lazy='joined',
backref='conquest_stats')
ConquestPokemonStat.stat = relationship(ConquestStat,
uselist=False,
innerjoin=True, lazy='joined',
backref='pokemon_stats')
ConquestWarrior.archetype = relationship(ConquestWarriorArchetype,
uselist=False,
backref=backref('warriors'))
ConquestWarrior.ranks = relationship(ConquestWarriorRank,
order_by=ConquestWarriorRank.rank,
innerjoin=True,
backref=backref('warrior', uselist=False))
ConquestWarrior.types = relationship(Type,
secondary=ConquestWarriorSpecialty.__table__,
order_by=ConquestWarriorSpecialty.slot,
innerjoin=True,
backref='conquest_warriors')
ConquestWarriorRank.skill = relationship(ConquestWarriorSkill,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('warrior_ranks', order_by=ConquestWarriorRank.id))
ConquestWarriorRank.stats = relationship(ConquestWarriorRankStatMap,
innerjoin=True,
order_by=ConquestWarriorRankStatMap.warrior_stat_id,
backref=backref('warrior_rank', uselist=False, innerjoin=True, lazy='joined'))
ConquestWarriorRankStatMap.stat = relationship(ConquestWarriorStat,
innerjoin=True, lazy='joined',
uselist=False,
backref='stat_map')
ConquestWarriorTransformation.completed_episode = relationship(ConquestEpisode,
primaryjoin=ConquestWarriorTransformation.completed_episode_id==ConquestEpisode.id,
uselist=False)
ConquestWarriorTransformation.current_episode = relationship(ConquestEpisode,
primaryjoin=ConquestWarriorTransformation.current_episode_id==ConquestEpisode.id,
uselist=False)
ConquestWarriorTransformation.distant_warrior = relationship(ConquestWarrior,
uselist=False)
ConquestWarriorTransformation.pokemon = relationship(PokemonSpecies,
secondary=ConquestTransformationPokemon.__table__,
order_by=PokemonSpecies.conquest_order)
ConquestWarriorTransformation.present_warriors = relationship(ConquestWarrior,
secondary=ConquestTransformationWarrior.__table__,
order_by=ConquestWarrior.id)
ConquestWarriorTransformation.type = relationship(Type,
uselist=False)
ConquestWarriorTransformation.warrior_rank = relationship(ConquestWarriorRank,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('transformation', uselist=False, innerjoin=True))
PokemonSpecies.conquest_abilities = relationship(Ability,
secondary=ConquestPokemonAbility.__table__,
order_by=ConquestPokemonAbility.slot,
backref=backref('conquest_pokemon', order_by=PokemonSpecies.conquest_order,
innerjoin=True))
PokemonSpecies.conquest_move = relationship(Move,
secondary=ConquestPokemonMove.__table__,
uselist=False,
backref=backref('conquest_pokemon', order_by=PokemonSpecies.conquest_order))
PokemonSpecies.conquest_evolution = relationship(ConquestPokemonEvolution,
uselist=False,
backref=backref('evolved_species', innerjoin=True, lazy='joined', uselist=False))

View file

@ -1,117 +1,15 @@
# encoding: utf8
u"""The Pokédex schema.
Columns have a info dictionary with these keys:
- official: True if the values appear in games or official material; False if
they are fan-created or fan-written. This flag is currently only set for
official text columns.
- format: The format of a text column. Can be one of:
- plaintext: Normal Unicode text (widely used in names)
- markdown: Veekun's Markdown flavor (generally used in effect descriptions)
- gametext: Transcription of in-game text that strives to be both
human-readable and represent the original text exactly.
- identifier: A fan-made identifier in the [-_a-z0-9]* format. Not intended
for translation.
- latex: A formula in LaTeX syntax.
- ripped: True for text that has been ripped from the games, and can be ripped
again for new versions or languages
- string_getter: for translation columns, a function taking (text, session,
language) that is used for properties on the main table. Used for Markdown
text.
See `pokedex.db.multilang` for how localizable text columns work. The session
classes in that module can be used to change the default language.
"""
# XXX: Check if "gametext" is set correctly everywhere
import collections
from functools import partial
from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, Table, UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
from sqlalchemy import Column, ForeignKey, PrimaryKeyConstraint, UniqueConstraint
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import backref, relationship
from sqlalchemy.orm.session import Session
from sqlalchemy.orm.interfaces import AttributeExtension
from sqlalchemy.sql import and_, or_
from sqlalchemy.schema import ColumnDefault
from sqlalchemy.sql import and_
from sqlalchemy.types import Boolean, Enum, Integer, SmallInteger, Unicode, UnicodeText
from pokedex.db import markdown, multilang
from pokedex.db import markdown
from pokedex.db.tables.base import TableBase, Language, create_translation_table
class TableSuperclass(object):
"""Superclass for declarative tables, to give them some generic niceties
like stringification.
"""
def __unicode__(self):
"""Be as useful as possible. Show the primary key, and an identifier
if we've got one.
"""
typename = u'.'.join((__name__, type(self).__name__))
pk_constraint = self.__table__.primary_key
if not pk_constraint:
return u"<%s object at %x>" % (typename, id(self))
pk = u', '.join(unicode(getattr(self, column.name))
for column in pk_constraint.columns)
try:
return u"<%s object (%s): %s>" % (typename, pk, self.identifier)
except AttributeError:
return u"<%s object (%s)>" % (typename, pk)
def __str__(self):
return unicode(self).encode('utf8')
def __repr__(self):
return unicode(self).encode('utf8')
mapped_classes = []
class TableMetaclass(DeclarativeMeta):
def __init__(cls, name, bases, attrs):
super(TableMetaclass, cls).__init__(name, bases, attrs)
if hasattr(cls, '__tablename__'):
mapped_classes.append(cls)
cls.translation_classes = []
metadata = MetaData()
TableBase = declarative_base(metadata=metadata, cls=TableSuperclass, metaclass=TableMetaclass)
### Need Language first, to create the partial() below
class Language(TableBase):
u"""A language the Pokémon games have been translated into."""
__tablename__ = 'languages'
__singlename__ = 'language'
id = Column(Integer, primary_key=True, nullable=False,
doc=u"A numeric ID")
iso639 = Column(Unicode(79), nullable=False,
doc=u"The two-letter code of the country where this language is spoken. Note that it is not unique.",
info=dict(format='identifier'))
iso3166 = Column(Unicode(79), nullable=False,
doc=u"The two-letter code of the language. Note that it is not unique.",
info=dict(format='identifier'))
identifier = Column(Unicode(79), nullable=False,
doc=u"An identifier",
info=dict(format='identifier'))
official = Column(Boolean, nullable=False, index=True,
doc=u"True iff games are produced in the language.")
order = Column(Integer, nullable=True,
doc=u"Order for sorting in foreign name lists.")
create_translation_table = partial(multilang.create_translation_table, language_class=Language)
create_translation_table('language_names', Language, 'names',
name = Column(Unicode(79), nullable=False, index=True,
doc=u"The name",
info=dict(format='plaintext', official=True)),
)
### The actual tables
class Ability(TableBase):
u"""An ability a Pokémon can have, such as Static or Pressure."""
@ -244,420 +142,6 @@ create_translation_table('characteristic_text', Characteristic, 'text',
info=dict(official=True, format='plaintext')),
)
class ConquestEpisode(TableBase):
u"""An episode from Pokémon Conquest: one of a bunch of mini-stories
featuring a particular warrior.
The main story, "The Legend of Ransei", also counts, even though it's not
in the episode select menu and there's no way to replay it.
"""
__tablename__ = 'conquest_episodes'
__singlename__ = 'episode'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this episode.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this episode.',
info=dict(format='identifier'))
create_translation_table('conquest_episode_names', ConquestEpisode, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestEpisodeWarrior(TableBase):
u"""A warrior featured in an episode in Pokémon Conquest.
This needs its own table because of the player having two episodes and
there being two players.
"""
__tablename__ = 'conquest_episode_warriors'
episode_id = Column(Integer, ForeignKey('conquest_episodes.id'), primary_key=True,
doc=u'The ID of the episode.')
warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), primary_key=True,
doc=u'The ID of the warrior.')
class ConquestKingdom(TableBase):
u"""A kingdom in Pokémon Conquest."""
__tablename__ = 'conquest_kingdoms'
__singlename__ = 'kingdom'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u"An ID for this kingdom.")
identifier = Column(Unicode(79), nullable=False,
doc=u"A readable identifier for this kingdom.",
info=dict(format='identifier'))
type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
doc=u"The type associated with this kingdom in-game.")
create_translation_table('conquest_kingdom_names', ConquestKingdom, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestMaxLink(TableBase):
u"""The maximum link a warrior rank can reach with a Pokémon in Pokémon Conquest."""
__tablename__ = 'conquest_max_links'
warrior_rank_id = Column(Integer, ForeignKey('conquest_warrior_ranks.id'), primary_key=True,
doc=u"The ID of the warrior rank.")
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True,
doc=u'The ID of the Pokémon species.')
max_link = Column(Integer, nullable=False,
doc=u'The maximum link percentage this warrior rank and Pokémon can reach.')
class ConquestMoveData(TableBase):
u"""Data about a move in Pokémon Conquest."""
__tablename__ = 'conquest_move_data'
move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the move.')
power = Column(Integer, nullable=True,
doc=u"The move's power, null if it does no damage.")
accuracy = Column(Integer, nullable=True,
doc=u"The move's base accuracy, null if it is self-targeted or never misses.")
effect_chance = Column(Integer, nullable=True,
doc=u"The chance as a percentage that the move's secondary effect will trigger.")
effect_id = Column(Integer, ForeignKey('conquest_move_effects.id'), nullable=False,
doc=u"The ID of the move's effect.")
range_id = Column(Integer, ForeignKey('conquest_move_ranges.id'), nullable=False,
doc=u"The ID of the move's range.")
displacement_id = Column(Integer, ForeignKey('conquest_move_displacements.id'), nullable=True,
doc=u"The ID of the move's displacement.")
@property
def star_rating(self):
"""Return the move's in-game power rating as a number of stars."""
if not self.power:
return 0
else:
stars = (self.power - 1) // 10
stars = min(stars, 5) # i.e. maximum of 5 stars
stars = max(stars, 1) # And minimum of 1
return stars
class ConquestMoveDisplacement(TableBase):
u"""A way in which a move can cause the user or target to move to a
different tile.
If a move displaces its user, the move's range is relative to the user's
original position.
"""
__tablename__ = 'conquest_move_displacements'
__singlename__ = 'move_displacement'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this displacement.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this displacement.',
info=dict(format='identifier'))
affects_target = Column(Boolean, nullable=False,
doc=u'True iff the move displaces its target(s) and not its user.')
create_translation_table('conquest_move_displacement_prose', ConquestMoveDisplacement, 'prose',
name = Column(Unicode(79), nullable=True,
doc=u'A name for the displacement.',
info=dict(format='plaintext')),
short_effect = Column(UnicodeText, nullable=True,
doc=u"A short summary of how the displacement works, to be used in the move's short effect.",
info=dict(format='markdown')),
effect = Column(UnicodeText, nullable=True,
doc=u"A detailed description of how the displacement works, to be used alongside the move's long effect.",
info=dict(format='markdown')),
)
class ConquestMoveEffect(TableBase):
u"""An effect moves can have in Pokémon Conquest."""
__tablename__ = 'conquest_move_effects'
__singlename__ = 'conquest_move_effect'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this effect.')
create_translation_table('conquest_move_effect_prose', ConquestMoveEffect, 'prose',
short_effect = Column(UnicodeText, nullable=True,
doc=u"A short summary of the effect",
info=dict(format='markdown')),
effect = Column(UnicodeText, nullable=True,
doc=u"A detailed description of the effect",
info=dict(format='markdown')),
)
class ConquestMoveRange(TableBase):
u"""A set of tiles moves can target in Pokémon Conquest."""
__tablename__ = 'conquest_move_ranges'
__singlename__ = 'conquest_move_range'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this range.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this range.',
info=dict(format='identifier'))
targets = Column(Integer, nullable=False,
doc=u'The number of tiles this range targets.')
create_translation_table('conquest_move_range_prose', ConquestMoveRange, 'prose',
name = Column(Unicode(79), nullable=True,
doc=u"A short name briefly describing the range",
info=dict(format='plaintext')),
description = Column(UnicodeText, nullable=True,
doc=u"A detailed description of the range",
info=dict(format='plaintext')),
)
class ConquestPokemonAbility(TableBase):
u"""An ability a Pokémon species has in Pokémon Conquest."""
__tablename__ = 'conquest_pokemon_abilities'
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True, nullable=False, autoincrement=False,
doc=u'The ID of the Pokémon species with this ability.')
slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
doc=u"The order abilities are listed in. Upon evolution, if a Pokémon's abilities change, it will receive the one in the same slot.")
ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
doc=u'The ID of the ability.')
class ConquestPokemonEvolution(TableBase):
u"""The conditions under which a Pokémon must successfully complete an
action to evolve in Pokémon Conquest.
Any condition may be null if it does not apply for a particular Pokémon.
"""
__tablename__ = 'conquest_pokemon_evolution'
evolved_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True, nullable=False,
doc=u"The ID of the post-evolution species.")
required_stat_id = Column(Integer, ForeignKey('conquest_stats.id'), nullable=True,
doc=u"The ID of the stat which minimum_stat applies to.")
minimum_stat = Column(Integer, nullable=True,
doc=u"The minimum value the Pokémon must have in a particular stat.")
minimum_link = Column(Integer, nullable=True,
doc=u"The minimum link percentage the Pokémon must have with its warrior.")
kingdom_id = Column(Integer, ForeignKey('conquest_kingdoms.id'), nullable=True,
doc=u"The ID of the kingdom in which this Pokémon must complete an action after meeting all other requirements.")
warrior_gender_id = Column(Integer, ForeignKey('genders.id'), nullable=True,
doc=u"The ID of the gender the Pokémon's warrior must be.")
item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
doc=u"The ID of the item the Pokémon's warrior must have equipped.")
recruiting_ko_required = Column(Boolean, nullable=False,
doc=u"If true, the Pokémon must KO a Pokémon under the right conditions to recruit that Pokémon's warrior.")
class ConquestPokemonMove(TableBase):
u"""A Pokémon's move in Pokémon Conquest.
Yes, "move"; each Pokémon has exactly one.
"""
__tablename__ = 'conquest_pokemon_moves'
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the Pokémon species.')
move_id = Column(Integer, ForeignKey('moves.id'), nullable=False,
doc=u'The ID of the move.')
class ConquestPokemonStat(TableBase):
u"""A Pokémon's base stat in Pokémon Conquest.
The main four base stats in Conquest are derived from level 100 stats in
the main series (ignoring effort, genes, and natures). Attack matches
either Attack or Special Attack, and Defense matches the average of Defense
and Special Defense. HP and Speed are the same.
"""
__tablename__ = 'conquest_pokemon_stats'
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the Pokémon species.')
conquest_stat_id = Column(Integer, ForeignKey('conquest_stats.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the stat.')
base_stat = Column(Integer, nullable=False,
doc=u'The base stat.')
class ConquestStat(TableBase):
u"""A stat Pokémon have in Pokémon Conquest."""
__tablename__ = 'conquest_stats'
__singlename__ = 'conquest_stat' # To be safe
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this stat.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this stat.',
info=dict(format='identifier'))
is_base = Column(Boolean, nullable=False,
doc=u'True iff this is one of the main stats, calculated for individual Pokémon.')
create_translation_table('conquest_stat_names', ConquestStat, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestTransformationPokemon(TableBase):
u"""A Pokémon that satisfies a warrior transformation's link condition.
If a warrior has one or more Pokémon listed here, they only need to raise
one of them to the required link.
"""
__tablename__ = 'conquest_transformation_pokemon'
transformation_id = Column(Integer, ForeignKey('conquest_warrior_transformation.transformed_warrior_rank_id'), primary_key=True,
doc=u'The ID of the corresponding transformation, in turn a warrior rank ID.')
pokemon_species_id = Column(Integer, ForeignKey('pokemon_species.id'), primary_key=True,
doc=u'The ID of the Pokémon species.')
class ConquestTransformationWarrior(TableBase):
u"""A warrior who must be present in the same nation as another warrior for
the latter to transform into their next rank.
If a warrior has one or more other warriors listed here, they *all* need to
gather in the same nation for the transformation to take place.
"""
__tablename__ = 'conquest_transformation_warriors'
transformation_id = Column(Integer, ForeignKey('conquest_warrior_transformation.transformed_warrior_rank_id'), primary_key=True,
doc=u'The ID of the corresponding transformation, in turn a warrior rank ID.')
present_warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), primary_key=True,
doc=u'The ID of the other warrior who must be present.')
class ConquestWarrior(TableBase):
u"""A warrior in Pokémon Conquest."""
__tablename__ = 'conquest_warriors'
__singlename__ = 'warrior'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=True,
doc=u'An ID for this warrior.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this warrior.',
info=dict(format='identifier'))
gender_id = Column(Integer, ForeignKey('genders.id'), nullable=False,
doc=u"The ID of the warrior's gender.")
archetype_id = Column(Integer, ForeignKey('conquest_warrior_archetypes.id'), nullable=True,
doc=u"The ID of this warrior's archetype. Null for unique warriors.")
create_translation_table('conquest_warrior_names', ConquestWarrior, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestWarriorArchetype(TableBase):
u"""An archetype that generic warriors in Pokémon Conquest can have. All
warriors of a particular archetype share sprites and dialogue.
Some of these are unused as warriors because they exist only as NPCs. They
should still be kept because we have their sprites and may eventually get
their dialogue.
"""
__tablename__ = 'conquest_warrior_archetypes'
__singlename__ = 'archetype'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this archetype.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier describing this archetype.',
info=dict(format='identifier'))
class ConquestWarriorRank(TableBase):
u"""A warrior at a particular rank in Pokémon Conquest.
These are used for whatever changes between ranks, much like Pokémon forms.
Generic warriors who have only one rank are also represented here, with a
single row.
To clarify, each warrior's ranks are individually called "warrior ranks"
here; for example, "Rank 2 Nobunaga" is an example of a warrior rank, not
just "Rank 2".
"""
__tablename__ = 'conquest_warrior_ranks'
__singlename__ = 'warrior_rank'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this warrior rank.')
warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), nullable=False,
doc=u'The ID of the warrior.')
rank = Column(Integer, nullable=False,
doc=u'The rank number.')
skill_id = Column(Integer, ForeignKey('conquest_warrior_skills.id'), nullable=False,
doc=u"The ID of this warrior rank's warrior skill.")
__table_args__ = (
UniqueConstraint(warrior_id, rank),
{},
)
class ConquestWarriorRankStatMap(TableBase):
u"""Any of a warrior rank's warrior stats in Pokémon Conquest."""
__tablename__ = 'conquest_warrior_rank_stat_map'
warrior_rank_id = Column(Integer, ForeignKey('conquest_warrior_ranks.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the warrior rank.')
warrior_stat_id = Column(Integer, ForeignKey('conquest_warrior_stats.id'), primary_key=True, autoincrement=False,
doc=u'The ID of the warrior stat.')
base_stat = Column(Integer, nullable=False,
doc=u'The stat.')
class ConquestWarriorSkill(TableBase):
u"""A warrior skill in Pokémon Conquest."""
__tablename__ = 'conquest_warrior_skills'
__singlename__ = 'skill'
id = Column(Integer, primary_key=True, nullable=False, autoincrement=True,
doc=u'An ID for this skill.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this skill.',
info=dict(format='identifier'))
create_translation_table('conquest_warrior_skill_names', ConquestWarriorSkill, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestWarriorSpecialty(TableBase):
u"""A warrior's specialty types in Pokémon Conquest.
These have no actual effect on gameplay; they just indicate which types of
Pokémon each warrior generally has strong maximum links with.
"""
__tablename__ = 'conquest_warrior_specialties'
warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), primary_key=True, nullable=False, autoincrement=False,
doc=u'The ID of the warrior.')
type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
doc=u'The ID of the type.')
slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
doc=u"The order in which the warrior's types are listed.")
class ConquestWarriorStat(TableBase):
u"""A stat that warriors have in Pokémon Conquest."""
__tablename__ = 'conquest_warrior_stats'
__singlename__ = 'warrior_stat'
id = Column(Integer, primary_key=True, autoincrement=True,
doc=u'An ID for this stat.')
identifier = Column(Unicode(79), nullable=False,
doc=u'A readable identifier for this stat.',
info=dict(format='identifier'))
create_translation_table('conquest_warrior_stat_names', ConquestWarriorStat, 'names',
relation_lazy='joined',
name=Column(Unicode(79), nullable=False, index=True,
doc=u'The name.',
info=dict(format='plaintext', official=True))
)
class ConquestWarriorTransformation(TableBase):
u"""The conditions under which a warrior must perform an action in order
to transform to the next rank.
Or most of them, anyway. See also ConquestTransformationPokemon and
ConquestTransformationWarrior.
"""
__tablename__ = 'conquest_warrior_transformation'
transformed_warrior_rank_id = Column(Integer, ForeignKey('conquest_warrior_ranks.id'), primary_key=True,
doc=u'The ID of the post-transformation warrior rank.')
is_automatic = Column(Boolean, nullable=False,
doc=u'True iff the transformation happens automatically in the story with no further requirements.')
required_link = Column(Integer, nullable=True,
doc=u'The link percentage the warrior must reach with one of several specific Pokémon, if any.')
completed_episode_id = Column(Integer, ForeignKey('conquest_episodes.id'), nullable=True,
doc=u'The ID of the episode the player must have completed, if any.')
current_episode_id = Column(Integer, ForeignKey('conquest_episodes.id'), nullable=True,
doc=u'The ID of the episode the player must currently be playing, if any.')
distant_warrior_id = Column(Integer, ForeignKey('conquest_warriors.id'), nullable=True,
doc=u'The ID of another warrior who must be in the army, but not in the same kingdom or in any adjacent kingdom.')
female_warlord_count = Column(Integer, nullable=True,
doc=u'The number of female warlords who must be in the same nation.')
pokemon_count = Column(Integer, nullable=True,
doc=u'The number of Pokémon that must be registered in the gallery.')
collection_type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
doc=u'The ID of a type all Pokémon of which must be registered in the gallery.')
warrior_count = Column(Integer, nullable=True,
doc=u'The number of warriors that must be registered in the gallery.')
class ContestCombo(TableBase):
u"""Combo of two moves in a Contest."""
__tablename__ = 'contest_combos'
@ -2257,113 +1741,6 @@ Characteristic.stat = relationship(Stat,
backref='characteristics')
ConquestEpisode.warriors = relationship(ConquestWarrior,
secondary=ConquestEpisodeWarrior.__table__,
innerjoin=True,
backref='episodes')
ConquestKingdom.type = relationship(Type,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('conquest_kingdom', uselist=False))
ConquestMaxLink.pokemon = relationship(PokemonSpecies,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('conquest_max_links', lazy='dynamic',
order_by=ConquestMaxLink.warrior_rank_id))
ConquestMaxLink.warrior_rank = relationship(ConquestWarriorRank,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('max_links', lazy='dynamic'))
ConquestMaxLink.warrior = association_proxy('warrior_rank', 'warrior')
ConquestMoveData.move_displacement = relationship(ConquestMoveDisplacement,
uselist=False,
backref='move_data')
ConquestMoveData.move = relationship(Move,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('conquest_data', uselist=False))
ConquestMoveData.move_effect = relationship(ConquestMoveEffect,
innerjoin=True, lazy='joined',
backref='move_data')
ConquestMoveData.range = relationship(ConquestMoveRange,
innerjoin=True, lazy='joined',
backref='move_data')
ConquestMoveData.effect = markdown.MoveEffectProperty('effect')
ConquestMoveData.effect_map = markdown.MoveEffectPropertyMap('effect_map')
ConquestMoveData.short_effect = markdown.MoveEffectProperty('short_effect')
ConquestMoveData.short_effect_map = markdown.MoveEffectPropertyMap('short_effect_map')
ConquestMoveData.displacement = markdown.MoveEffectProperty('effect', relationship='move_displacement')
ConquestPokemonEvolution.gender = relationship(Gender,
backref='conquest_evolutions')
ConquestPokemonEvolution.item = relationship(Item,
backref='conquest_evolutions')
ConquestPokemonEvolution.kingdom = relationship(ConquestKingdom,
backref='evolutions')
ConquestPokemonEvolution.stat = relationship(ConquestStat,
backref='evolutions')
ConquestPokemonStat.pokemon = relationship(PokemonSpecies,
uselist=False,
innerjoin=True, lazy='joined',
backref='conquest_stats')
ConquestPokemonStat.stat = relationship(ConquestStat,
uselist=False,
innerjoin=True, lazy='joined',
backref='pokemon_stats')
ConquestWarrior.archetype = relationship(ConquestWarriorArchetype,
uselist=False,
backref=backref('warriors'))
ConquestWarrior.ranks = relationship(ConquestWarriorRank,
order_by=ConquestWarriorRank.rank,
innerjoin=True,
backref=backref('warrior', uselist=False))
ConquestWarrior.types = relationship(Type,
secondary=ConquestWarriorSpecialty.__table__,
order_by=ConquestWarriorSpecialty.slot,
innerjoin=True,
backref='conquest_warriors')
ConquestWarriorRank.skill = relationship(ConquestWarriorSkill,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('warrior_ranks', order_by=ConquestWarriorRank.id))
ConquestWarriorRank.stats = relationship(ConquestWarriorRankStatMap,
innerjoin=True,
order_by=ConquestWarriorRankStatMap.warrior_stat_id,
backref=backref('warrior_rank', uselist=False, innerjoin=True, lazy='joined'))
ConquestWarriorRankStatMap.stat = relationship(ConquestWarriorStat,
innerjoin=True, lazy='joined',
uselist=False,
backref='stat_map')
ConquestWarriorTransformation.completed_episode = relationship(ConquestEpisode,
primaryjoin=ConquestWarriorTransformation.completed_episode_id==ConquestEpisode.id,
uselist=False)
ConquestWarriorTransformation.current_episode = relationship(ConquestEpisode,
primaryjoin=ConquestWarriorTransformation.current_episode_id==ConquestEpisode.id,
uselist=False)
ConquestWarriorTransformation.distant_warrior = relationship(ConquestWarrior,
uselist=False)
ConquestWarriorTransformation.pokemon = relationship(PokemonSpecies,
secondary=ConquestTransformationPokemon.__table__,
order_by=PokemonSpecies.conquest_order)
ConquestWarriorTransformation.present_warriors = relationship(ConquestWarrior,
secondary=ConquestTransformationWarrior.__table__,
order_by=ConquestWarrior.id)
ConquestWarriorTransformation.type = relationship(Type,
uselist=False)
ConquestWarriorTransformation.warrior_rank = relationship(ConquestWarriorRank,
uselist=False,
innerjoin=True, lazy='joined',
backref=backref('transformation', uselist=False, innerjoin=True))
ContestCombo.first = relationship(Move,
primaryjoin=ContestCombo.first_move_id==Move.id,
@ -2805,19 +2182,6 @@ PokemonSpecies.pal_park = relationship(PalPark,
uselist=False,
backref='species')
PokemonSpecies.conquest_abilities = relationship(Ability,
secondary=ConquestPokemonAbility.__table__,
order_by=ConquestPokemonAbility.slot,
backref=backref('conquest_pokemon', order_by=PokemonSpecies.conquest_order,
innerjoin=True))
PokemonSpecies.conquest_move = relationship(Move,
secondary=ConquestPokemonMove.__table__,
uselist=False,
backref=backref('conquest_pokemon', order_by=PokemonSpecies.conquest_order))
PokemonSpecies.conquest_evolution = relationship(ConquestPokemonEvolution,
uselist=False,
backref=backref('evolved_species', innerjoin=True, lazy='joined', uselist=False))
PokemonSpeciesFlavorText.version = relationship(Version, innerjoin=True, lazy='joined')
PokemonSpeciesFlavorText.language = relationship(Language, innerjoin=True, lazy='joined')

View file

@ -2,7 +2,7 @@
import pytest
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy import Column, Integer, String, Unicode, create_engine
from sqlalchemy.orm import class_mapper, joinedload, sessionmaker
from sqlalchemy.orm.session import Session
from sqlalchemy.ext.declarative import declarative_base
@ -31,16 +31,6 @@ def test_variable_names_2(table):
"""We also want all of the tables exported"""
assert getattr(tables, table.__name__) is table
def test_class_order():
"""The declarative classes should be defined in alphabetical order.
Except for Language which should be first.
"""
class_names = [table.__name__ for table in tables.mapped_classes]
def key(name):
return name != 'Language', name
print [(a,b) for (a,b) in zip(class_names, sorted(class_names, key=key)) if a!=b]
assert class_names == sorted(class_names, key=key)
def test_i18n_table_creation():
"""Creates and manipulates a magical i18n table, completely independent of
the existing schema and data. Makes sure that the expected behavior of the
@ -190,7 +180,7 @@ def test_texts(cls):
pytest.fail('%s: official text with bad format' % column)
text_columns.append(column)
else:
if isinstance(column.type, tables.Unicode):
if isinstance(column.type, Unicode):
pytest.fail('%s: text column without format' % column)
if column.name == 'name' and format != 'plaintext':
pytest.fail('%s: non-plaintext name' % column)