03e85412728b88df11ca1e6e7282dc5127814fc7
[zzz-pokedex.git] / pokedex / db / tables.py
1 # encoding: utf8
2
3 u"""The Pokédex schema
4
5 Columns have a info dictionary with these keys:
6 - description: The description of the column
7 - official: True if the values appear in games or official material; False if
8 they are fan-created or fan-written. This flag is currently only set for
9 official text columns.
10 - markup: The format of a text column. Can be one of:
11 - plaintext: Normal Unicode text (widely used in names)
12 - markdown: Veekun's Markdown flavor (generally used in effect descriptions)
13 - gametext: Transcription of in-game text that strives to be both
14 human-readable and represent the original text exactly.
15 - identifier: A fan-made identifier in the [-_a-z0-9]* format. Not intended
16 for translation.
17 - latex: A formula in LaTeX syntax.
18
19 See `pokedex.db.multilang` for how localizable text columns work. The session
20 classes in that module can be used to change the default language.
21 """
22 # XXX: Check if "gametext" is set correctly everywhere
23
24 import collections
25 from functools import partial
26
27 from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, Table, UniqueConstraint
28 from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
29 from sqlalchemy.ext.associationproxy import association_proxy
30 from sqlalchemy.orm import backref, relation
31 from sqlalchemy.orm.session import Session
32 from sqlalchemy.orm.interfaces import AttributeExtension
33 from sqlalchemy.sql import and_
34 from sqlalchemy.schema import ColumnDefault
35 from sqlalchemy.types import *
36
37 from pokedex.db import markdown, multilang
38
39 class TableSuperclass(object):
40 """Superclass for declarative tables, to give them some generic niceties
41 like stringification.
42 """
43 def __unicode__(self):
44 """Be as useful as possible. Show the primary key, and an identifier
45 if we've got one.
46 """
47 typename = u'.'.join((__name__, type(self).__name__))
48
49 pk_constraint = self.__table__.primary_key
50 if not pk_constraint:
51 return u"<%s object at %x>" % (typename, id(self))
52
53 pk = u', '.join(unicode(getattr(self, column.name))
54 for column in pk_constraint.columns)
55 try:
56 return u"<%s object (%s): %s>" % (typename, pk, self.identifier)
57 except AttributeError:
58 return u"<%s object (%s)>" % (typename, pk)
59
60 def __str__(self):
61 return unicode(self).encode('utf8')
62
63 mapped_classes = []
64 class TableMetaclass(DeclarativeMeta):
65 def __init__(cls, name, bases, attrs):
66 super(TableMetaclass, cls).__init__(name, bases, attrs)
67 if hasattr(cls, '__tablename__'):
68 mapped_classes.append(cls)
69 cls.translation_classes = []
70
71 metadata = MetaData()
72 TableBase = declarative_base(metadata=metadata, cls=TableSuperclass, metaclass=TableMetaclass)
73
74
75 ### Need Language first, to create the partial() below
76
77 class Language(TableBase):
78 u"""A language the Pokémon games have been translated into
79 """
80 __tablename__ = 'languages'
81 __singlename__ = 'language'
82 id = Column(Integer, primary_key=True, nullable=False,
83 info=dict(description="A numeric ID"))
84 iso639 = Column(Unicode(2), nullable=False,
85 info=dict(description="The two-letter code of the country where this language is spoken. Note that it is not unique.", format='identifier'))
86 iso3166 = Column(Unicode(2), nullable=False,
87 info=dict(description="The two-letter code of the language. Note that it is not unique.", format='identifier'))
88 identifier = Column(Unicode(16), nullable=False,
89 info=dict(description="An identifier", format='identifier'))
90 official = Column(Boolean, nullable=False, index=True,
91 info=dict(description=u"True iff games are produced in the language."))
92 order = Column(Integer, nullable=True,
93 info=dict(description=u"Order for sorting in foreign name lists."))
94
95 create_translation_table = partial(multilang.create_translation_table, language_class=Language)
96
97 create_translation_table('language_names', Language, 'names',
98 name = Column(Unicode(16), nullable=False, index=True,
99 info=dict(description="The name", format='plaintext', official=True)),
100 )
101
102 ### The actual tables
103
104 class Ability(TableBase):
105 u"""An ability a Pokémon can have, such as Static or Pressure.
106 """
107 __tablename__ = 'abilities'
108 __singlename__ = 'ability'
109 id = Column(Integer, primary_key=True, nullable=False,
110 info=dict(description="This ability's unique ID; matches the games' internal ID"))
111 identifier = Column(Unicode(24), nullable=False,
112 info=dict(description="An identifier", format='identifier'))
113 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
114 info=dict(description="The ID of the generation this ability was introduced in", detail=True))
115
116 create_translation_table('ability_names', Ability, 'names',
117 relation_lazy='joined',
118 name = Column(Unicode(24), nullable=False, index=True,
119 info=dict(description="The name", format='plaintext', official=True)),
120 )
121 create_translation_table('ability_prose', Ability, 'prose',
122 effect = Column(markdown.MarkdownColumn(5120), nullable=False,
123 info=dict(description="A detailed description of this ability's effect", format='markdown')),
124 short_effect = Column(markdown.MarkdownColumn(255), nullable=False,
125 info=dict(description="A short summary of this ability's effect", format='markdown')),
126 )
127
128 class AbilityChangelog(TableBase):
129 """History of changes to abilities across main game versions."""
130 __tablename__ = 'ability_changelog'
131 __singlename__ = 'ability_changelog'
132 id = Column(Integer, primary_key=True, nullable=False,
133 info=dict(description="This change's unique ID"))
134 ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
135 info=dict(description="The ID of the ability that changed"))
136 changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
137 info=dict(description="The ID of the version group in which the ability changed"))
138
139 create_translation_table('ability_changelog_prose', AbilityChangelog, 'prose',
140 effect = Column(markdown.MarkdownColumn(255), nullable=False,
141 info=dict(description="A description of the old behavior", format='markdown'))
142 )
143
144 class AbilityFlavorText(TableBase):
145 u"""In-game flavor text of an ability
146 """
147 __tablename__ = 'ability_flavor_text'
148 ability_id = Column(Integer, ForeignKey('abilities.id'), primary_key=True, nullable=False, autoincrement=False,
149 info=dict(description="The ID of the ability"))
150 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
151 info=dict(description="The ID of the version group this flavor text is taken from"))
152 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
153 info=dict(description="The language"))
154 flavor_text = Column(Unicode(64), nullable=False,
155 info=dict(description="The actual flavor text", official=True, format='gametext'))
156
157 class Berry(TableBase):
158 u"""A Berry, consumable item that grows on trees
159
160 For data common to all items, such as the name, see the corresponding item entry.
161 """
162 __tablename__ = 'berries'
163 id = Column(Integer, primary_key=True, nullable=False,
164 info=dict(description="This Berry's in-game number"))
165 item_id = Column(Integer, ForeignKey('items.id'), nullable=False,
166 info=dict(description="The ID of the item that represents this Berry"))
167 firmness_id = Column(Integer, ForeignKey('berry_firmness.id'), nullable=False,
168 info=dict(description="The ID of this Berry's firmness category"))
169 natural_gift_power = Column(Integer, nullable=True,
170 info=dict(description="Natural Gift's power when used with this Berry"))
171 natural_gift_type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
172 info=dict(description="The ID of the Type that Natural Gift has when used with this Berry"))
173 size = Column(Integer, nullable=False,
174 info=dict(description=u"The size of this Berry, in millimeters"))
175 max_harvest = Column(Integer, nullable=False,
176 info=dict(description="The maximum number of these berries that can grow on one tree in Generation IV"))
177 growth_time = Column(Integer, nullable=False,
178 info=dict(description="Time it takes the tree to grow one stage, in hours. Berry trees go through four of these growth stages before they can be picked."))
179 soil_dryness = Column(Integer, nullable=False,
180 info=dict(description="The speed at which this Berry dries out the soil as it grows. A higher rate means the soil dries more quickly."))
181 smoothness = Column(Integer, nullable=False,
182 info=dict(description="The smoothness of this Berry, used in making Pokéblocks or Poffins"))
183
184 class BerryFirmness(TableBase):
185 u"""A Berry firmness, such as "hard" or "very soft".
186 """
187 __tablename__ = 'berry_firmness'
188 __singlename__ = 'berry_firmness'
189 id = Column(Integer, primary_key=True, nullable=False,
190 info=dict(description="A unique ID for this firmness"))
191 identifier = Column(Unicode(10), nullable=False,
192 info=dict(description="An identifier", format='identifier'))
193
194 create_translation_table('berry_firmness_names', BerryFirmness, 'names',
195 relation_lazy='joined',
196 name = Column(Unicode(10), nullable=False, index=True,
197 info=dict(description="The name", format='plaintext', official=True)),
198 )
199
200 class BerryFlavor(TableBase):
201 u"""A Berry flavor level.
202 """
203 __tablename__ = 'berry_flavors'
204 berry_id = Column(Integer, ForeignKey('berries.id'), primary_key=True, nullable=False, autoincrement=False,
205 info=dict(description="The ID of the berry"))
206 contest_type_id = Column(Integer, ForeignKey('contest_types.id'), primary_key=True, nullable=False, autoincrement=False,
207 info=dict(description="The ID of the flavor"))
208 flavor = Column(Integer, nullable=False,
209 info=dict(description="The level of the flavor in the berry"))
210
211 class ContestCombo(TableBase):
212 u"""Combo of two moves in a Contest.
213 """
214 __tablename__ = 'contest_combos'
215 first_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
216 info=dict(description="The ID of the first move in the combo"))
217 second_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
218 info=dict(description="The ID of the second and final move in the combo"))
219
220 class ContestEffect(TableBase):
221 u"""Effect of a move when used in a Contest.
222 """
223 __tablename__ = 'contest_effects'
224 __singlename__ = 'contest_effect'
225 id = Column(Integer, primary_key=True, nullable=False,
226 info=dict(description="A unique ID for this effect"))
227 appeal = Column(SmallInteger, nullable=False,
228 info=dict(description="The base number of hearts the user of this move gets"))
229 jam = Column(SmallInteger, nullable=False,
230 info=dict(description="The base number of hearts the user's opponent loses"))
231
232 create_translation_table('contest_effect_prose', ContestEffect, 'prose',
233 flavor_text = Column(Unicode(64), nullable=False,
234 info=dict(description="The in-game description of this effect", official=True, format='gametext')),
235 effect = Column(Unicode(255), nullable=False,
236 info=dict(description="A detailed description of the effect", format='plaintext')),
237 )
238
239 class ContestType(TableBase):
240 u"""A Contest type, such as "cool" or "smart", and their associated Berry flavors and Pokéblock colors.
241 """
242 __tablename__ = 'contest_types'
243 __singlename__ = 'contest_type'
244 id = Column(Integer, primary_key=True, nullable=False,
245 info=dict(description="A unique ID for this Contest type"))
246 identifier = Column(Unicode(6), nullable=False,
247 info=dict(description="An identifier", format='identifier'))
248
249 create_translation_table('contest_type_names', ContestType, 'names',
250 relation_lazy='joined',
251 name = Column(Unicode(6), nullable=False, index=True,
252 info=dict(description="The name", format='plaintext', official=True)),
253 flavor = Column(Unicode(6), nullable=False,
254 info=dict(description="The name of the corresponding Berry flavor", official=True, format='plaintext')),
255 color = Column(Unicode(6), nullable=False,
256 info=dict(description=u"The name of the corresponding Pokéblock color", official=True, format='plaintext')),
257 )
258
259 class EggGroup(TableBase):
260 u"""An Egg group. Usually, two Pokémon can breed if they share an Egg Group.
261
262 (exceptions are the Ditto and No Eggs groups)
263 """
264 __tablename__ = 'egg_groups'
265 __singlename__ = 'egg_group'
266 id = Column(Integer, primary_key=True, nullable=False,
267 info=dict(description="A unique ID for this group"))
268 identifier = Column(Unicode(16), nullable=False,
269 info=dict(description=u"An identifier.", format='identifier'))
270
271 create_translation_table('egg_group_prose', EggGroup, 'names',
272 relation_lazy='joined',
273 name = Column(Unicode(16), nullable=False, index=True,
274 info=dict(description="The name", format='plaintext', official=True)),
275 )
276
277 class Encounter(TableBase):
278 u"""Encounters with wild Pokémon.
279
280 Bear with me, here.
281
282 Within a given area in a given game, encounters are differentiated by the
283 "slot" they are in and the state of the game world.
284
285 What the player is doing to get an encounter, such as surfing or walking
286 through tall grass, is called terrain. Each terrain has its own set of
287 encounter slots.
288
289 Within a terrain, slots are defined primarily by rarity. Each slot can
290 also be affected by world conditions; for example, the 20% slot for walking
291 in tall grass is affected by whether a swarm is in effect in that area.
292 "Is there a swarm?" is a condition; "there is a swarm" and "there is not a
293 swarm" are the possible values of this condition.
294
295 A slot (20% walking in grass) and any appropriate world conditions (no
296 swarm) are thus enough to define a specific encounter.
297
298 Well, okay, almost: each slot actually appears twice.
299 """
300
301 __tablename__ = 'encounters'
302 id = Column(Integer, primary_key=True, nullable=False,
303 info=dict(description="A unique ID for this encounter"))
304 version_id = Column(Integer, ForeignKey('versions.id'), nullable=False, autoincrement=False,
305 info=dict(description="The ID of the version this applies to"))
306 location_area_id = Column(Integer, ForeignKey('location_areas.id'), nullable=False, autoincrement=False,
307 info=dict(description="The ID of the location of this encounter"))
308 encounter_slot_id = Column(Integer, ForeignKey('encounter_slots.id'), nullable=False, autoincrement=False,
309 info=dict(description="The ID of the encounter slot, which determines terrain and rarity"))
310 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
311 info=dict(description=u"The ID of the encountered Pokémon"))
312 min_level = Column(Integer, nullable=False, autoincrement=False,
313 info=dict(description=u"The minimum level of the encountered Pokémon"))
314 max_level = Column(Integer, nullable=False, autoincrement=False,
315 info=dict(description=u"The maxmum level of the encountered Pokémon"))
316
317 class EncounterCondition(TableBase):
318 u"""A conditions in the game world that affects Pokémon encounters, such as time of day.
319 """
320
321 __tablename__ = 'encounter_conditions'
322 __singlename__ = 'encounter_condition'
323 id = Column(Integer, primary_key=True, nullable=False,
324 info=dict(description="A unique ID for this condition"))
325 identifier = Column(Unicode(64), nullable=False,
326 info=dict(description="An identifier", format='identifier'))
327
328 create_translation_table('encounter_condition_prose', EncounterCondition, 'prose',
329 name = Column(Unicode(64), nullable=False, index=True,
330 info=dict(description="The name", format='plaintext', official=False)),
331 )
332
333 class EncounterConditionValue(TableBase):
334 u"""A possible state for a condition; for example, the state of 'swarm' could be 'swarm' or 'no swarm'.
335 """
336
337 __tablename__ = 'encounter_condition_values'
338 __singlename__ = 'encounter_condition_value'
339 id = Column(Integer, primary_key=True, nullable=False,
340 info=dict(description="A numeric ID"))
341 encounter_condition_id = Column(Integer, ForeignKey('encounter_conditions.id'), primary_key=False, nullable=False, autoincrement=False,
342 info=dict(description="The ID of the encounter condition this is a value of"))
343 identifier = Column(Unicode(64), nullable=False,
344 info=dict(description="An identifier", format='identifier'))
345 is_default = Column(Boolean, nullable=False,
346 info=dict(description='Set if this value is the default state for the condition'))
347
348 create_translation_table('encounter_condition_value_prose', EncounterConditionValue, 'prose',
349 name = Column(Unicode(64), nullable=False, index=True,
350 info=dict(description="The name", format='plaintext', official=False)),
351 )
352
353 class EncounterConditionValueMap(TableBase):
354 u"""Maps encounters to the specific conditions under which they occur.
355 """
356 __tablename__ = 'encounter_condition_value_map'
357 encounter_id = Column(Integer, ForeignKey('encounters.id'), primary_key=True, nullable=False, autoincrement=False,
358 info=dict(description="The ID of the encounter"))
359 encounter_condition_value_id = Column(Integer, ForeignKey('encounter_condition_values.id'), primary_key=True, nullable=False, autoincrement=False,
360 info=dict(description="The ID of the encounter condition value"))
361
362 class EncounterSlot(TableBase):
363 u"""An abstract "slot" within a terrain, associated with both some set of conditions and a rarity.
364
365 Note that there are two encounters per slot, so the rarities will only add
366 up to 50.
367 """
368
369 __tablename__ = 'encounter_slots'
370 id = Column(Integer, primary_key=True, nullable=False,
371 info=dict(description="A unique ID for this slot"))
372 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, autoincrement=False,
373 info=dict(description="The ID of the version group this slot is in"))
374 encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=False, nullable=False, autoincrement=False,
375 info=dict(description="The ID of the terrain"))
376 slot = Column(Integer, nullable=True,
377 info=dict(description="This slot's order for the location and terrain"))
378 rarity = Column(Integer, nullable=False,
379 info=dict(description="The chance of the encounter as a percentage"))
380
381 class EncounterTerrain(TableBase):
382 u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
383 """
384
385 __tablename__ = 'encounter_terrain'
386 __singlename__ = __tablename__
387 id = Column(Integer, primary_key=True, nullable=False,
388 info=dict(description="A unique ID for the terrain"))
389 identifier = Column(Unicode(64), nullable=False,
390 info=dict(description="An identifier", format='identifier'))
391
392 create_translation_table('encounter_terrain_prose', EncounterTerrain, 'prose',
393 name = Column(Unicode(64), nullable=False, index=True,
394 info=dict(description="The name", format='plaintext', official=False)),
395 )
396
397 class EvolutionChain(TableBase):
398 u"""A family of Pokémon that are linked by evolution
399 """
400 __tablename__ = 'evolution_chains'
401 id = Column(Integer, primary_key=True, nullable=False,
402 info=dict(description="A numeric ID"))
403 growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), nullable=False,
404 info=dict(description="ID of the growth rate for this family"))
405 baby_trigger_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
406 info=dict(description="Item that a parent must hold while breeding to produce a baby"))
407
408 class EvolutionTrigger(TableBase):
409 u"""An evolution type, such as "level" or "trade".
410 """
411 __tablename__ = 'evolution_triggers'
412 __singlename__ = 'evolution_trigger'
413 id = Column(Integer, primary_key=True, nullable=False,
414 info=dict(description="A numeric ID"))
415 identifier = Column(Unicode(16), nullable=False,
416 info=dict(description="An identifier", format='identifier'))
417
418 create_translation_table('evolution_trigger_prose', EvolutionTrigger, 'prose',
419 name = Column(Unicode(16), nullable=False, index=True,
420 info=dict(description="The name", format='plaintext', official=False)),
421 )
422
423 class Experience(TableBase):
424 u"""EXP needed for a certain level with a certain growth rate
425 """
426 __tablename__ = 'experience'
427 growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), primary_key=True, nullable=False,
428 info=dict(description="ID of the growth rate"))
429 level = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
430 info=dict(description="The level"))
431 experience = Column(Integer, nullable=False,
432 info=dict(description="The number of EXP points needed to get to that level"))
433
434 class Generation(TableBase):
435 u"""A Generation of the Pokémon franchise
436 """
437 __tablename__ = 'generations'
438 __singlename__ = 'generation'
439 id = Column(Integer, primary_key=True, nullable=False,
440 info=dict(description="A numeric ID"))
441 main_region_id = Column(Integer, ForeignKey('regions.id'),
442 info=dict(description="ID of the region this generation's main games take place in"))
443 canonical_pokedex_id = Column(Integer, ForeignKey('pokedexes.id'),
444 info=dict(description=u"ID of the Pokédex this generation's main games use by default"))
445 identifier = Column(Unicode(16), nullable=False,
446 info=dict(description=u'An identifier', format='identifier'))
447
448 create_translation_table('generation_names', Generation, 'names',
449 relation_lazy='joined',
450 name = Column(Unicode(16), nullable=False, index=True,
451 info=dict(description="The name", format='plaintext', official=True)),
452 )
453
454 class GrowthRate(TableBase):
455 u"""Growth rate of a Pokémon, i.e. the EXP → level function.
456 """
457 __tablename__ = 'growth_rates'
458 __singlename__ = 'growth_rate'
459 id = Column(Integer, primary_key=True, nullable=False,
460 info=dict(description="A numeric ID"))
461 identifier = Column(Unicode(20), nullable=False,
462 info=dict(description="An identifier", format='identifier'))
463 formula = Column(Unicode(500), nullable=False,
464 info=dict(description="The formula", format='latex'))
465
466 create_translation_table('growth_rate_prose', GrowthRate, 'prose',
467 name = Column(Unicode(20), nullable=False, index=True,
468 info=dict(description="The name", format='plaintext', official=False)),
469 )
470
471 class Item(TableBase):
472 u"""An Item from the games, like "Poké Ball" or "Bicycle".
473 """
474 __tablename__ = 'items'
475 __singlename__ = 'item'
476 id = Column(Integer, primary_key=True, nullable=False,
477 info=dict(description="A numeric ID"))
478 identifier = Column(Unicode(20), nullable=False,
479 info=dict(description="An identifier", format='identifier'))
480 category_id = Column(Integer, ForeignKey('item_categories.id'), nullable=False,
481 info=dict(description="ID of a category this item belongs to"))
482 cost = Column(Integer, nullable=False,
483 info=dict(description=u"Cost of the item when bought. Items sell for half this price."))
484 fling_power = Column(Integer, nullable=True,
485 info=dict(description=u"Power of the move Fling when used with this item."))
486 fling_effect_id = Column(Integer, ForeignKey('item_fling_effects.id'), nullable=True,
487 info=dict(description=u"ID of the fling-effect of the move Fling when used with this item. Note that these are different from move effects."))
488
489 @property
490 def appears_underground(self):
491 u"""True if the item appears underground, as specified by the appropriate flag
492 """
493 return any(flag.identifier == u'underground' for flag in self.flags)
494
495 create_translation_table('item_names', Item, 'names',
496 relation_lazy='joined',
497 name = Column(Unicode(20), nullable=False, index=True,
498 info=dict(description="The name", format='plaintext', official=True)),
499 )
500 create_translation_table('item_prose', Item, 'prose',
501 short_effect = Column(Unicode(256), nullable=False,
502 info=dict(description="A short summary of the effect", format='plaintext')),
503 effect = Column(markdown.MarkdownColumn(5120), nullable=False,
504 info=dict(description=u"Detailed description of the item's effect.", format='markdown')),
505 )
506 create_translation_table('item_flavor_summaries', Item, 'flavor_summaries',
507 flavor_summary = Column(Unicode(512), nullable=True,
508 info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext'))
509 )
510
511 class ItemCategory(TableBase):
512 u"""An item category
513 """
514 # XXX: This is fanon, right?
515 __tablename__ = 'item_categories'
516 __singlename__ = 'item_category'
517 id = Column(Integer, primary_key=True, nullable=False,
518 info=dict(description="A numeric ID"))
519 pocket_id = Column(Integer, ForeignKey('item_pockets.id'), nullable=False,
520 info=dict(description="ID of the pocket these items go to"))
521 identifier = Column(Unicode(16), nullable=False,
522 info=dict(description="An identifier", format='identifier'))
523
524 create_translation_table('item_category_prose', ItemCategory, 'prose',
525 relation_lazy='joined',
526 name = Column(Unicode(16), nullable=False, index=True,
527 info=dict(description="The name", format='plaintext', official=False)),
528 )
529
530 class ItemFlag(TableBase):
531 u"""An item attribute such as "consumable" or "holdable".
532 """
533 __tablename__ = 'item_flags'
534 __singlename__ = 'item_flag'
535 id = Column(Integer, primary_key=True, nullable=False,
536 info=dict(description="A numeric ID"))
537 identifier = Column(Unicode(24), nullable=False,
538 info=dict(description="Identifier of the flag", format='identifier'))
539
540 create_translation_table('item_flag_prose', ItemFlag, 'prose',
541 name = Column(Unicode(24), nullable=False, index=True,
542 info=dict(description="The name", format='plaintext', official=False)),
543 description = Column(Unicode(64), nullable=False,
544 info=dict(description="Short description of the flag", format='plaintext')),
545 )
546
547 class ItemFlagMap(TableBase):
548 u"""Maps an item flag to its item.
549 """
550 __tablename__ = 'item_flag_map'
551 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
552 info=dict(description="The ID of the item"))
553 item_flag_id = Column(Integer, ForeignKey('item_flags.id'), primary_key=True, autoincrement=False, nullable=False,
554 info=dict(description="The ID of the item flag"))
555
556 class ItemFlavorText(TableBase):
557 u"""An in-game description of an item
558 """
559 __tablename__ = 'item_flavor_text'
560 __singlename__ = 'item_flavor_text'
561 summary_column = Item.flavor_summaries_table, 'flavor_summary'
562 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
563 info=dict(description="The ID of the item"))
564 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False,
565 info=dict(description="ID of the version group that sports this text"))
566 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
567 info=dict(description="The language"))
568 flavor_text = Column(Unicode(255), nullable=False,
569 info=dict(description="The flavor text itself", official=True, format='gametext'))
570
571 class ItemFlingEffect(TableBase):
572 u"""An effect of the move Fling when used with a specific item
573 """
574 __tablename__ = 'item_fling_effects'
575 __singlename__ = 'item_fling_effect'
576 id = Column(Integer, primary_key=True, nullable=False,
577 info=dict(description="A numeric ID"))
578
579 create_translation_table('item_fling_effect_prose', ItemFlingEffect, 'prose',
580 effect = Column(Unicode(255), nullable=False,
581 info=dict(description="Description of the effect", format='plaintext')),
582 )
583
584 class ItemGameIndex(TableBase):
585 u"""The internal ID number a game uses for an item
586 """
587 __tablename__ = 'item_game_indices'
588 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
589 info=dict(description="The database ID of the item"))
590 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
591 info=dict(description="ID of the generation of games"))
592 game_index = Column(Integer, nullable=False,
593 info=dict(description="Internal ID of the item in the generation"))
594
595 class ItemPocket(TableBase):
596 u"""A pocket that categorizes items
597 """
598 __tablename__ = 'item_pockets'
599 __singlename__ = 'item_pocket'
600 id = Column(Integer, primary_key=True, nullable=False,
601 info=dict(description="A numeric ID"))
602 identifier = Column(Unicode(16), nullable=False,
603 info=dict(description="An identifier of this pocket", format='identifier'))
604
605 create_translation_table('item_pocket_names', ItemPocket, 'names',
606 relation_lazy='joined',
607 name = Column(Unicode(16), nullable=False, index=True,
608 info=dict(description="The name", format='plaintext', official=True)),
609 )
610
611 class Location(TableBase):
612 u"""A place in the Pokémon world
613 """
614 __tablename__ = 'locations'
615 __singlename__ = 'location'
616 id = Column(Integer, primary_key=True, nullable=False,
617 info=dict(description="A numeric ID"))
618 region_id = Column(Integer, ForeignKey('regions.id'),
619 info=dict(description="ID of the region this location is in"))
620 identifier = Column(Unicode(64), nullable=False,
621 info=dict(description="An identifier", format='identifier'))
622
623 create_translation_table('location_names', Location, 'names',
624 relation_lazy='joined',
625 name = Column(Unicode(64), nullable=False, index=True,
626 info=dict(description="The name", format='plaintext', official=True)),
627 )
628
629 class LocationArea(TableBase):
630 u"""A sub-area of a location
631 """
632 __tablename__ = 'location_areas'
633 __singlename__ = 'location_area'
634 id = Column(Integer, primary_key=True, nullable=False,
635 info=dict(description="A numeric ID"))
636 location_id = Column(Integer, ForeignKey('locations.id'), nullable=False,
637 info=dict(description="ID of the location this area is part of"))
638 game_index = Column(Integer, nullable=False,
639 info=dict(description="ID the games ude for this area"))
640 identifier = Column(Unicode(64), nullable=True,
641 info=dict(description="An identifier", format='identifier'))
642
643 create_translation_table('location_area_prose', LocationArea, 'prose',
644 relation_lazy='joined',
645 name = Column(Unicode(64), nullable=False, index=True,
646 info=dict(description="The name", format='plaintext', official=False)),
647 )
648
649 class LocationAreaEncounterRate(TableBase):
650 # XXX: What's this exactly? Someone add the docstring & revise the descriptions
651 __tablename__ = 'location_area_encounter_rates'
652 location_area_id = Column(Integer, ForeignKey('location_areas.id'), primary_key=True, nullable=False, autoincrement=False,
653 info=dict(description="ID of the area"))
654 encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=True, nullable=False, autoincrement=False,
655 info=dict(description="ID of the terrain"))
656 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, autoincrement=False,
657 info=dict(description="ID of the version"))
658 rate = Column(Integer, nullable=True,
659 info=dict(description="The encounter rate")) # units?
660
661 class LocationGameIndex(TableBase):
662 u"""IDs the games use internally for locations
663 """
664 __tablename__ = 'location_game_indices'
665 location_id = Column(Integer, ForeignKey('locations.id'), nullable=False, primary_key=True,
666 info=dict(description="Database ID of the locaion"))
667 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True,
668 info=dict(description="ID of the generation this entry to"))
669 game_index = Column(Integer, nullable=False,
670 info=dict(description="Internal game ID of the location"))
671
672 class Machine(TableBase):
673 u"""A TM or HM; numbered item that can teach a move to a Pokémon
674 """
675 __tablename__ = 'machines'
676 machine_number = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
677 info=dict(description="Number of the machine for TMs, or 100 + the munber for HMs"))
678 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
679 info=dict(description="Versions this entry applies to"))
680 item_id = Column(Integer, ForeignKey('items.id'), nullable=False,
681 info=dict(description="ID of the corresponding Item"))
682 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False,
683 info=dict(description="ID of the taught move"))
684
685 @property
686 def is_hm(self):
687 u"""True if this machine is a HM, False if it's a TM
688 """
689 return self.machine_number >= 100
690
691 class Move(TableBase):
692 u"""A Move: technique or attack a Pokémon can learn to use
693 """
694 __tablename__ = 'moves'
695 __singlename__ = 'move'
696 id = Column(Integer, primary_key=True, nullable=False,
697 info=dict(description="A numeric ID"))
698 identifier = Column(Unicode(24), nullable=False,
699 info=dict(description="An identifier", format='identifier'))
700 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
701 info=dict(description="ID of the generation this move first appeared in"))
702 type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
703 info=dict(description="ID of the move's elemental type"))
704 power = Column(SmallInteger, nullable=False,
705 info=dict(description="Base power of the move"))
706 pp = Column(SmallInteger, nullable=True,
707 info=dict(description="Base PP (Power Points) of the move, nullable if not applicable (e.g. Struggle and Shadow moves)."))
708 accuracy = Column(SmallInteger, nullable=True,
709 info=dict(description="Accuracy of the move; NULL means it never misses"))
710 priority = Column(SmallInteger, nullable=False,
711 info=dict(description="The move's priority bracket"))
712 target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False,
713 info=dict(description="ID of the target (range) of the move"))
714 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False,
715 info=dict(description="ID of the damage class (physical/special) of the move"))
716 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
717 info=dict(description="ID of the move's effect"))
718 effect_chance = Column(Integer, nullable=True,
719 info=dict(description="The chance for a secondary effect. What this is a chance of is specified by the move's effect."))
720 contest_type_id = Column(Integer, ForeignKey('contest_types.id'), nullable=True,
721 info=dict(description="ID of the move's Contest type (e.g. cool or smart)"))
722 contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True,
723 info=dict(description="ID of the move's Contest effect"))
724 super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=True,
725 info=dict(description="ID of the move's Super Contest effect"))
726
727 create_translation_table('move_names', Move, 'names',
728 relation_lazy='joined',
729 name = Column(Unicode(24), nullable=False, index=True,
730 info=dict(description="The name", format='plaintext', official=True))
731 )
732 create_translation_table('move_flavor_summaries', Move, 'flavor_summaries',
733 flavor_summary = Column(Unicode(512), nullable=True,
734 info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext'))
735 )
736
737 class MoveBattleStyle(TableBase):
738 u"""A battle style of a move""" # XXX: Explain better
739 __tablename__ = 'move_battle_styles'
740 __singlename__ = 'move_battle_style'
741 id = Column(Integer, primary_key=True, nullable=False,
742 info=dict(description="A numeric ID"))
743 identifier = Column(Unicode(8), nullable=False,
744 info=dict(description="An identifier", format='identifier'))
745
746 create_translation_table('move_battle_style_prose', MoveBattleStyle, 'prose',
747 relation_lazy='joined',
748 name = Column(Unicode(8), nullable=False, index=True,
749 info=dict(description="The name", format='plaintext', official=False)),
750 )
751
752 class MoveChangelog(TableBase):
753 """History of changes to moves across main game versions."""
754 __tablename__ = 'move_changelog'
755 __singlename__ = 'move_changelog'
756 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
757 info=dict(description="ID of the move that changed"))
758 changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
759 info=dict(description="ID of the version group in which the move changed"))
760 type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
761 info=dict(description="Prior type of the move, or NULL if unchanged"))
762 power = Column(SmallInteger, nullable=True,
763 info=dict(description="Prior base power of the move, or NULL if unchanged"))
764 pp = Column(SmallInteger, nullable=True,
765 info=dict(description="Prior base PP of the move, or NULL if unchanged"))
766 accuracy = Column(SmallInteger, nullable=True,
767 info=dict(description="Prior accuracy of the move, or NULL if unchanged"))
768 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=True,
769 info=dict(description="Prior ID of the effect, or NULL if unchanged"))
770 effect_chance = Column(Integer, nullable=True,
771 info=dict(description="Prior effect chance, or NULL if unchanged"))
772
773 class MoveDamageClass(TableBase):
774 u"""Any of the damage classes moves can have, i.e. physical, special, or non-damaging.
775 """
776 __tablename__ = 'move_damage_classes'
777 __singlename__ = 'move_damage_class'
778 id = Column(Integer, primary_key=True, nullable=False,
779 info=dict(description="A numeric ID"))
780 identifier = Column(Unicode(16), nullable=False,
781 info=dict(description="An identifier", format='identifier'))
782
783 create_translation_table('move_damage_class_prose', MoveDamageClass, 'prose',
784 relation_lazy='joined',
785 name = Column(Unicode(16), nullable=False, index=True,
786 info=dict(description="The name", format='plaintext', official=False)),
787 description = Column(Unicode(64), nullable=False,
788 info=dict(description="A description of the class", format='plaintext')),
789 )
790
791 class MoveEffect(TableBase):
792 u"""An effect of a move
793 """
794 __tablename__ = 'move_effects'
795 __singlename__ = 'move_effect'
796 id = Column(Integer, primary_key=True, nullable=False,
797 info=dict(description="A numeric ID"))
798
799 create_translation_table('move_effect_prose', MoveEffect, 'prose',
800 short_effect = Column(Unicode(256), nullable=False,
801 info=dict(description="A short summary of the effect", format='plaintext')),
802 effect = Column(Unicode(5120), nullable=False,
803 info=dict(description="A detailed description of the effect", format='plaintext')),
804 )
805
806 class MoveEffectCategory(TableBase):
807 u"""Category of a move effect
808 """
809 __tablename__ = 'move_effect_categories'
810 __singlename__ = 'move_effect_category'
811 id = Column(Integer, primary_key=True, nullable=False,
812 info=dict(description="A numeric ID"))
813 identifier = Column(Unicode(64), nullable=False,
814 info=dict(description="An identifier", format='identifier'))
815 can_affect_user = Column(Boolean, nullable=False,
816 info=dict(description="Set if the user can be affected"))
817
818 create_translation_table('move_effect_category_prose', MoveEffectCategory, 'prose',
819 name = Column(Unicode(64), nullable=False, index=True,
820 info=dict(description="The name", format='plaintext', official=False)),
821 )
822
823 class MoveEffectCategoryMap(TableBase):
824 u"""Maps a move effect category to a move effect
825 """
826 __tablename__ = 'move_effect_category_map'
827 move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False,
828 info=dict(description="ID of the move effect"))
829 move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False,
830 info=dict(description="ID of the category"))
831 affects_user = Column(Boolean, primary_key=True, nullable=False,
832 info=dict(description="Set if the user is affected"))
833
834 class MoveEffectChangelog(TableBase):
835 """History of changes to move effects across main game versions."""
836 __tablename__ = 'move_effect_changelog'
837 __singlename__ = 'move_effect_changelog'
838 id = Column(Integer, primary_key=True, nullable=False,
839 info=dict(description="A numeric ID"))
840 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
841 info=dict(description="The ID of the effect that changed"))
842 changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
843 info=dict(description="The ID of the version group in which the effect changed"))
844
845 __table_args__ = (
846 UniqueConstraint(effect_id, changed_in_version_group_id),
847 {},
848 )
849
850 create_translation_table('move_effect_changelog_prose', MoveEffectChangelog, 'prose',
851 effect = Column(markdown.MarkdownColumn(512), nullable=False,
852 info=dict(description="A description of the old behavior", format='markdown')),
853 )
854
855 class MoveFlag(TableBase):
856 u"""Maps a move flag to a move
857 """
858 # XXX: Other flags have a ___Flag class for the actual flag and ___FlagMap for the map,
859 # these, somewhat confusingly, have MoveFlagType and MoveFlag
860 __tablename__ = 'move_flags'
861 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
862 info=dict(description="ID of the move"))
863 move_flag_type_id = Column(Integer, ForeignKey('move_flag_types.id'), primary_key=True, nullable=False, autoincrement=False,
864 info=dict(description="ID of the flag"))
865
866 class MoveFlagType(TableBase):
867 u"""A Move attribute such as "snatchable" or "contact".
868 """
869 __tablename__ = 'move_flag_types'
870 __singlename__ = 'move_flag_type'
871 id = Column(Integer, primary_key=True, nullable=False,
872 info=dict(description="A numeric ID"))
873 identifier = Column(Unicode(32), nullable=False,
874 info=dict(description="A short identifier for the flag", format='identifier'))
875
876 create_translation_table('move_flag_type_prose', MoveFlagType, 'prose',
877 relation_lazy='joined',
878 name = Column(Unicode(32), nullable=False, index=True,
879 info=dict(description="The name", format='plaintext', official=False)),
880 description = Column(markdown.MarkdownColumn(128), nullable=False,
881 info=dict(description="A short description of the flag", format='markdown')),
882 )
883
884 class MoveFlavorText(TableBase):
885 u"""In-game description of a move
886 """
887 __tablename__ = 'move_flavor_text'
888 summary_column = Move.flavor_summaries_table, 'flavor_summary'
889 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
890 info=dict(description="ID of the move"))
891 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
892 info=dict(description="ID of the version group this text appears in"))
893 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
894 info=dict(description="The language"))
895 flavor_text = Column(Unicode(255), nullable=False,
896 info=dict(description="The flavor text", official=True, format='gametext'))
897
898 class MoveMeta(TableBase):
899 u"""Metadata for move effects, sorta-kinda ripped straight from the game"""
900 __tablename__ = 'move_meta'
901 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
902 info=dict(description="A numeric ID"))
903 meta_category_id = Column(Integer, ForeignKey('move_meta_categories.id'), nullable=False,
904 info=dict(description="ID of the move category"))
905 meta_ailment_id = Column(Integer, ForeignKey('move_meta_ailments.id'), nullable=False,
906 info=dict(description="ID of the caused ailment"))
907 min_hits = Column(Integer, nullable=True, index=True,
908 info=dict(description="Minimum number of hits per use"))
909 max_hits = Column(Integer, nullable=True, index=True,
910 info=dict(description="Maximum number of hits per use"))
911 min_turns = Column(Integer, nullable=True, index=True,
912 info=dict(description="Minimum number of turns the user is forced to use the move"))
913 max_turns = Column(Integer, nullable=True, index=True,
914 info=dict(description="Maximum number of turns the user is forced to use the move"))
915 recoil = Column(Integer, nullable=False, index=True,
916 info=dict(description="Recoil damage, in percent of damage done"))
917 healing = Column(Integer, nullable=False, index=True,
918 info=dict(description="Healing, in percent of user's max HP"))
919 crit_rate = Column(Integer, nullable=False, index=True,
920 info=dict(description="Critical hit rate bonus"))
921 ailment_chance = Column(Integer, nullable=False, index=True,
922 info=dict(description="Chance to cause an ailment, in percent"))
923 flinch_chance = Column(Integer, nullable=False, index=True,
924 info=dict(description="Chance to cause flinching, in percent"))
925 stat_chance = Column(Integer, nullable=False, index=True,
926 info=dict(description="Chance to cause a stat change, in percent"))
927
928 class MoveMetaAilment(TableBase):
929 u"""Common status ailments moves can inflict on a single Pokémon, including
930 major ailments like paralysis and minor ailments like trapping.
931 """
932 __tablename__ = 'move_meta_ailments'
933 __singlename__ = 'move_meta_ailment'
934 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
935 info=dict(description="A numeric ID"))
936 identifier = Column(Unicode(24), nullable=False,
937 info=dict(description="An identifier", format='identifier'))
938
939 create_translation_table('move_meta_ailment_names', MoveMetaAilment, 'names',
940 relation_lazy='joined',
941 name = Column(Unicode(24), nullable=False, index=True,
942 info=dict(description="The name", format='plaintext', official=True)),
943 )
944
945 class MoveMetaCategory(TableBase):
946 u"""Very general categories that loosely group move effects."""
947 __tablename__ = 'move_meta_categories'
948 __singlename__ = 'move_meta_category'
949 id = Column(Integer, primary_key=True, nullable=False,
950 info=dict(description="A numeric ID"))
951
952 create_translation_table('move_meta_category_prose', MoveMetaCategory, 'prose',
953 relation_lazy='joined',
954 description = Column(Unicode(64), nullable=False,
955 info=dict(description="A description of the category", format="plaintext", official=False)),
956 )
957
958 class MoveMetaStatChange(TableBase):
959 u"""Stat changes moves (may) make."""
960 __tablename__ = 'move_meta_stat_changes'
961 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
962 info=dict(description="ID of the move"))
963 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False,
964 info=dict(description="ID of the stat"))
965 change = Column(Integer, nullable=False, index=True,
966 info=dict(description="Amount of increase/decrease, in stages"))
967
968 class MoveTarget(TableBase):
969 u"""Targetting or "range" of a move, e.g. "Affects all opponents" or "Affects user".
970 """
971 __tablename__ = 'move_targets'
972 __singlename__ = 'move_target'
973 id = Column(Integer, primary_key=True, nullable=False,
974 info=dict(description="A numeric ID"))
975 identifier = Column(Unicode(32), nullable=False,
976 info=dict(description="An identifier", format='identifier'))
977
978 create_translation_table('move_target_prose', MoveTarget, 'prose',
979 relation_lazy='joined',
980 name = Column(Unicode(32), nullable=False, index=True,
981 info=dict(description="The name", format='plaintext', official=False)),
982 description = Column(Unicode(128), nullable=False,
983 info=dict(description="A description", format='plaintext')),
984 )
985
986 class Nature(TableBase):
987 u"""A nature a Pokémon can have, such as Calm or Brave
988 """
989 __tablename__ = 'natures'
990 __singlename__ = 'nature'
991 id = Column(Integer, primary_key=True, nullable=False,
992 info=dict(description="A numeric ID"))
993 identifier = Column(Unicode(8), nullable=False,
994 info=dict(description="An identifier", format='identifier'))
995 decreased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
996 info=dict(description="ID of the stat that this nature decreases by 10% (if decreased_stat_id is the same, the effects cancel out)"))
997 increased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
998 info=dict(description="ID of the stat that this nature increases by 10% (if decreased_stat_id is the same, the effects cancel out)"))
999 hates_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False,
1000 info=dict(description=u"ID of the Berry flavor the Pokémon hates (if likes_flavor_id is the same, the effects cancel out)"))
1001 likes_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False,
1002 info=dict(description=u"ID of the Berry flavor the Pokémon likes (if hates_flavor_id is the same, the effects cancel out)"))
1003
1004 @property
1005 def is_neutral(self):
1006 u"""Returns True iff this nature doesn't alter a Pokémon's stats,
1007 bestow taste preferences, etc.
1008 """
1009 return self.increased_stat_id == self.decreased_stat_id
1010
1011 create_translation_table('nature_names', Nature, 'names',
1012 relation_lazy='joined',
1013 name = Column(Unicode(8), nullable=False, index=True,
1014 info=dict(description="The name", format='plaintext', official=True)),
1015 )
1016
1017 class NatureBattleStylePreference(TableBase):
1018 u"""Battle Palace move preference
1019
1020 Specifies how likely a Pokémon with a specific Nature is to use a move of
1021 a particular battl style in Battle Palace or Battle Tent
1022 """
1023 __tablename__ = 'nature_battle_style_preferences'
1024 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
1025 info=dict(description=u"ID of the Pokémon's nature"))
1026 move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False,
1027 info=dict(description="ID of the battle style"))
1028 low_hp_preference = Column(Integer, nullable=False,
1029 info=dict(description=u"Chance of using the move, in percent, if HP is under ½"))
1030 high_hp_preference = Column(Integer, nullable=False,
1031 info=dict(description=u"Chance of using the move, in percent, if HP is over ½"))
1032
1033 class NaturePokeathlonStat(TableBase):
1034 u"""Specifies how a Nature affects a Pokéathlon stat
1035 """
1036 __tablename__ = 'nature_pokeathlon_stats'
1037 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
1038 info=dict(description="ID of the nature"))
1039 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False,
1040 info=dict(description="ID of the stat"))
1041 max_change = Column(Integer, nullable=False,
1042 info=dict(description="Maximum change"))
1043
1044 class PokeathlonStat(TableBase):
1045 u"""A Pokéathlon stat, such as "Stamina" or "Jump".
1046 """
1047 __tablename__ = 'pokeathlon_stats'
1048 __singlename__ = 'pokeathlon_stat'
1049 id = Column(Integer, primary_key=True, nullable=False,
1050 info=dict(description="A numeric ID"))
1051 identifier = Column(Unicode(8), nullable=False,
1052 info=dict(description="An identifier", format='identifier'))
1053
1054 create_translation_table('pokeathlon_stat_names', PokeathlonStat, 'names',
1055 name = Column(Unicode(8), nullable=False, index=True,
1056 info=dict(description="The name", format='plaintext', official=True)),
1057 )
1058
1059 class Pokedex(TableBase):
1060 u"""A collection of Pokémon species ordered in a particular way
1061 """
1062 __tablename__ = 'pokedexes'
1063 __singlename__ = 'pokedex'
1064 id = Column(Integer, primary_key=True, nullable=False,
1065 info=dict(description="A numeric ID"))
1066 region_id = Column(Integer, ForeignKey('regions.id'), nullable=True,
1067 info=dict(description=u"ID of the region this Pokédex is used in, or None if it's global"))
1068 identifier = Column(Unicode(16), nullable=False,
1069 info=dict(description=u"An identifier", format='identifier'))
1070
1071 create_translation_table('pokedex_prose', Pokedex, 'prose',
1072 relation_lazy='joined',
1073 name = Column(Unicode(16), nullable=False, index=True,
1074 info=dict(description="The name", format='plaintext', official=False)),
1075 description = Column(Unicode(512), nullable=False,
1076 info=dict(description=u"A longer description of the Pokédex", format='plaintext')),
1077 )
1078
1079 class Pokemon(TableBase):
1080 u"""A species of Pokémon. The core to this whole mess.
1081 """
1082 __tablename__ = 'pokemon'
1083 __singlename__ = 'pokemon'
1084 id = Column(Integer, primary_key=True, nullable=False,
1085 info=dict(description=u"A numeric ID"))
1086 identifier = Column(Unicode(20), nullable=False,
1087 info=dict(description=u"An identifier", format='identifier'))
1088 generation_id = Column(Integer, ForeignKey('generations.id'),
1089 info=dict(description=u"ID of the generation this species first appeared in"))
1090 evolution_chain_id = Column(Integer, ForeignKey('evolution_chains.id'),
1091 info=dict(description=u"ID of the species' evolution chain (a.k.a. family)"))
1092 height = Column(Integer, nullable=False,
1093 info=dict(description=u"The height of the Pokémon, in decimeters (tenths of a meter)"))
1094 weight = Column(Integer, nullable=False,
1095 info=dict(description=u"The weight of the Pokémon, in tenths of a kilogram (decigrams)"))
1096 color_id = Column(Integer, ForeignKey('pokemon_colors.id'), nullable=False,
1097 info=dict(description=u"ID of this Pokémon's Pokédex color, as used for a gimmick search function in the games."))
1098 pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=False,
1099 info=dict(description=u"ID of this Pokémon's body shape, as used for a gimmick search function in the games."))
1100 habitat_id = Column(Integer, ForeignKey('pokemon_habitats.id'), nullable=True,
1101 info=dict(description=u"ID of this Pokémon's habitat, as used for a gimmick search function in the games."))
1102 gender_rate = Column(Integer, nullable=False,
1103 info=dict(description=u"The chance of this Pokémon being female, in eighths; or -1 for genderless"))
1104 capture_rate = Column(Integer, nullable=False,
1105 info=dict(description=u"The base capture rate; up to 255"))
1106 base_experience = Column(Integer, nullable=False,
1107 info=dict(description=u"The base EXP gained when defeating this Pokémon")) # XXX: Is this correct?
1108 base_happiness = Column(Integer, nullable=False,
1109 info=dict(description=u"The tameness when caught by a normal ball"))
1110 is_baby = Column(Boolean, nullable=False,
1111 info=dict(description=u"True iff the Pokémon is a baby, i.e. a lowest-stage Pokémon that cannot breed but whose evolved form can."))
1112 hatch_counter = Column(Integer, nullable=False,
1113 info=dict(description=u"Initial hatch counter: one must walk 255 × (hatch_counter + 1) steps before this Pokémon's egg hatches, unless utilizing bonuses like Flame Body's"))
1114 has_gender_differences = Column(Boolean, nullable=False,
1115 info=dict(description=u"Set iff the species exhibits enough sexual dimorphism to have separate sets of sprites in Gen IV and beyond."))
1116 order = Column(Integer, nullable=False, index=True,
1117 info=dict(description=u"Order for sorting. Almost national order, except families and forms are grouped together."))
1118
1119 ### Stuff to handle alternate Pokémon forms
1120
1121 @property
1122 def form(self):
1123 u"""Returns the Pokémon's form, using its default form as fallback."""
1124
1125 return self.unique_form or self.default_form
1126
1127 @property
1128 def is_base_form(self):
1129 u"""Returns True iff the Pokémon is the base form for its species,
1130 e.g. Land Shaymin.
1131 """
1132
1133 return self.unique_form is None or self.unique_form.is_default
1134
1135 @property
1136 def form_name(self):
1137 u"""Returns the Pokémon's form name if it represents a particular form
1138 and that form has a name, or None otherwise.
1139 """
1140
1141 # If self.unique_form is None, the short-circuit "and" will go ahead
1142 # and return that. Otherwise, it'll return the form's name, which may
1143 # also be None.
1144 return self.unique_form and self.unique_form.name
1145
1146 @property
1147 def full_name(self):
1148 u"""Returns the Pokémon's name, including its form if applicable."""
1149
1150 if self.form_name:
1151 return u'{0} {1}'.format(self.form_name, self.name)
1152 else:
1153 return self.name
1154
1155 @property
1156 def normal_form(self):
1157 u"""Returns the normal form for this Pokémon; i.e., this will return
1158 regular Deoxys when called on any Deoxys form.
1159 """
1160
1161 if self.unique_form:
1162 return self.unique_form.form_base_pokemon
1163 return self
1164
1165 ### Not forms!
1166
1167 def stat(self, stat_name):
1168 u"""Returns a PokemonStat record for the given stat name (or Stat row
1169 object). Uses the normal has-many machinery, so all the stats are
1170 effectively cached.
1171 """
1172 if isinstance(stat_name, Stat):
1173 stat_name = stat_name.name
1174
1175 for pokemon_stat in self.stats:
1176 if pokemon_stat.stat.name == stat_name:
1177 return pokemon_stat
1178
1179 raise KeyError(u'No stat named %s' % stat_name)
1180
1181 @property
1182 def better_damage_class(self):
1183 u"""Returns the MoveDamageClass that this Pokémon is best suited for,
1184 based on its attack stats.
1185
1186 If the attack stats are about equal (within 5), returns None. The
1187 value None, not the damage class called 'None'.
1188 """
1189 phys = self.stat(u'Attack')
1190 spec = self.stat(u'Special Attack')
1191
1192 diff = phys.base_stat - spec.base_stat
1193
1194 if diff > 5:
1195 return phys.stat.damage_class
1196 elif diff < -5:
1197 return spec.stat.damage_class
1198 else:
1199 return None
1200
1201 create_translation_table('pokemon_names', Pokemon, 'names',
1202 relation_lazy='joined',
1203 name = Column(Unicode(20), nullable=False, index=True,
1204 info=dict(description="The name", format='plaintext', official=True)),
1205 species = Column(Unicode(16), nullable=False,
1206 info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
1207 official=True, format='plaintext')),
1208 )
1209 create_translation_table('pokemon_flavor_summaries', Pokemon, 'flavor_summaries',
1210 flavor_summary = Column(Unicode(512), nullable=True,
1211 info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext'))
1212 )
1213
1214 class PokemonAbility(TableBase):
1215 u"""Maps an ability to a Pokémon that can have it
1216 """
1217 __tablename__ = 'pokemon_abilities'
1218 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1219 info=dict(description=u"ID of the Pokémon"))
1220 ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
1221 info=dict(description=u"ID of the ability"))
1222 # XXX having both a method and a slot is kind of gross. "slot" is a
1223 # misnomer, anyway: duplicate abilities don't appear in slot 2.
1224 # Probably should replace that with "order".
1225 is_dream = Column(Boolean, nullable=False, index=True,
1226 info=dict(description=u"Whether this is a Dream World ability"))
1227 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1228 info=dict(description=u"The ability slot, i.e. 1 or 2 for gen. IV"))
1229
1230 class PokemonColor(TableBase):
1231 u"""The "Pokédex color" of a Pokémon species. Usually based on the Pokémon's color.
1232 """
1233 __tablename__ = 'pokemon_colors'
1234 __singlename__ = 'pokemon_color'
1235 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1236 info=dict(description=u"ID of the Pokémon"))
1237 identifier = Column(Unicode(6), nullable=False,
1238 info=dict(description=u"An identifier", format='identifier'))
1239
1240 create_translation_table('pokemon_color_names', PokemonColor, 'names',
1241 relation_lazy='joined',
1242 name = Column(Unicode(6), nullable=False, index=True,
1243 info=dict(description="The name", format='plaintext', official=True)),
1244 )
1245
1246 class PokemonDexNumber(TableBase):
1247 u"""The number of a Pokémon in a particular Pokédex (e.g. Jigglypuff is #138 in Hoenn's 'dex)
1248 """
1249 __tablename__ = 'pokemon_dex_numbers'
1250 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1251 info=dict(description=u"ID of the Pokémon"))
1252 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), primary_key=True, nullable=False, autoincrement=False,
1253 info=dict(description=u"ID of the Pokédex"))
1254 pokedex_number = Column(Integer, nullable=False,
1255 info=dict(description=u"Number of the Pokémon in that the Pokédex"))
1256
1257 class PokemonEggGroup(TableBase):
1258 u"""Maps an Egg group to a Pokémon; each Pokémon belongs to one or two egg groups
1259 """
1260 __tablename__ = 'pokemon_egg_groups'
1261 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1262 info=dict(description=u"ID of the Pokémon"))
1263 egg_group_id = Column(Integer, ForeignKey('egg_groups.id'), primary_key=True, nullable=False, autoincrement=False,
1264 info=dict(description=u"ID of the egg group"))
1265
1266 class PokemonEvolution(TableBase):
1267 u"""A required action ("trigger") and the conditions under which the trigger
1268 must occur to cause a Pokémon to evolve.
1269
1270 Any condition may be null if it does not apply for a particular Pokémon.
1271 """
1272 __tablename__ = 'pokemon_evolution'
1273 from_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False,
1274 info=dict(description=u"The ID of the pre-evolution Pokémon."))
1275 to_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1276 info=dict(description=u"The ID of the post-evolution Pokémon."))
1277 evolution_trigger_id = Column(Integer, ForeignKey('evolution_triggers.id'), nullable=False,
1278 info=dict(description=u"The ID of the evolution trigger."))
1279 trigger_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
1280 info=dict(description=u"The ID of the item that must be used on the Pokémon."))
1281 minimum_level = Column(Integer, nullable=True,
1282 info=dict(description=u"The minimum level for the Pokémon."))
1283 gender = Column(Enum('male', 'female', name='pokemon_evolution_gender'), nullable=True,
1284 info=dict(description=u"The Pokémon's required gender, or None if gender doesn't matter"))
1285 location_id = Column(Integer, ForeignKey('locations.id'), nullable=True,
1286 info=dict(description=u"The ID of the location the evolution must be triggered at."))
1287 held_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
1288 info=dict(description=u"The ID of the item the Pokémon must hold."))
1289 time_of_day = Column(Enum('day', 'night', name='pokemon_evolution_time_of_day'), nullable=True,
1290 info=dict(description=u"The required time of day."))
1291 known_move_id = Column(Integer, ForeignKey('moves.id'), nullable=True,
1292 info=dict(description=u"The ID of the move the Pokémon must know."))
1293 minimum_happiness = Column(Integer, nullable=True,
1294 info=dict(description=u"The minimum happiness value the Pokémon must have."))
1295 minimum_beauty = Column(Integer, nullable=True,
1296 info=dict(description=u"The minimum Beauty value the Pokémon must have."))
1297 relative_physical_stats = Column(Integer, nullable=True,
1298 info=dict(description=u"The required relation between the Pokémon's Attack and Defense stats, as sgn(atk-def)."))
1299 party_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True,
1300 info=dict(description=u"The ID of the Pokémon that must be present in the party."))
1301 trade_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True,
1302 info=dict(description=u"The ID of the Pokémon for which this Pokémon must be traded."))
1303
1304 class PokemonFlavorText(TableBase):
1305 u"""In-game Pokédex descrption of a Pokémon.
1306 """
1307 __tablename__ = 'pokemon_flavor_text'
1308 summary_column = Pokemon.flavor_summaries_table, 'flavor_summary'
1309 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1310 info=dict(description=u"ID of the Pokémon"))
1311 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
1312 info=dict(description=u"ID of the version that has this flavor text"))
1313 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
1314 info=dict(description="The language"))
1315 flavor_text = Column(Unicode(255), nullable=False,
1316 info=dict(description=u"The flavor text", official=True, format='gametext'))
1317
1318 class PokemonForm(TableBase):
1319 u"""An individual form of a Pokémon.
1320
1321 Pokémon that do not have separate forms are still given a single row to
1322 represent their single form.
1323 """
1324 __tablename__ = 'pokemon_forms'
1325 __singlename__ = 'pokemon_form'
1326 id = Column(Integer, primary_key=True, nullable=False,
1327 info=dict(description=u'A unique ID for this form.'))
1328 identifier = Column(Unicode(16), nullable=True,
1329 info=dict(description=u"An identifier", format='identifier'))
1330 form_base_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
1331 info=dict(description=u'The ID of the base Pokémon for this form.'))
1332 unique_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), autoincrement=False,
1333 info=dict(description=u'The ID of a Pokémon that represents specifically this form, for Pokémon with functionally-different forms like Wormadam.'))
1334 introduced_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), autoincrement=False,
1335 info=dict(description=u'The ID of the version group in which this form first appeared.'))
1336 is_default = Column(Boolean, nullable=False,
1337 info=dict(description=u'Set for exactly one form used as the default for each species.'))
1338 order = Column(Integer, nullable=False, autoincrement=False,
1339 info=dict(description=u'The order in which forms should be sorted. Multiple forms may have equal order, in which case they should fall back on sorting by name.'))
1340
1341 @property
1342 def pokemon(self):
1343 u"""Returns the Pokémon for this form, using the form base as fallback.
1344 """
1345
1346 return self.unique_pokemon or self.form_base_pokemon
1347
1348 @property
1349 def full_name(self):
1350 u"""Returns the full name of this form, e.g. "Plant Cloak"."""
1351
1352 if not self.name:
1353 return None
1354 elif self.form_group and self.form_group.term:
1355 return u'{0} {1}'.format(self.name, self.form_group.term)
1356 else:
1357 return self.name
1358
1359 @property
1360 def pokemon_name(self):
1361 u"""Returns the name of this Pokémon with this form, e.g. "Plant
1362 Burmy".
1363 """
1364
1365 if self.name:
1366 return u'{0} {1}'.format(self.name, self.form_base_pokemon.name)
1367 else:
1368 return self.form_base_pokemon.name
1369
1370 create_translation_table('pokemon_form_names', PokemonForm, 'names',
1371 relation_lazy='joined',
1372 name = Column(Unicode(16), nullable=False, index=True,
1373 info=dict(description="The name", format='plaintext', official=True)),
1374 )
1375
1376 class PokemonFormGroup(TableBase):
1377 u"""Information about a Pokémon's forms as a group."""
1378 __tablename__ = 'pokemon_form_groups'
1379 __singlename__ = 'pokemon_form_group'
1380 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1381 info=dict(description=u"ID of the base form Pokémon"))
1382 is_battle_only = Column(Boolean, nullable=False,
1383 info=dict(description=u"Set iff the forms only change in battle"))
1384 # FIXME remooove
1385 PokemonFormGroup.id = PokemonFormGroup.pokemon_id
1386
1387 create_translation_table('pokemon_form_group_prose', PokemonFormGroup, 'prose',
1388 term = Column(Unicode(16), nullable=True,
1389 info=dict(description=u"The term for this Pokémon's forms, e.g. \"Cloak\" for Burmy or \"Forme\" for Deoxys.", official=True, format='plaintext')),
1390 description = Column(markdown.MarkdownColumn(1024), nullable=False,
1391 info=dict(description=u"Description of how the forms work", format='markdown')),
1392 )
1393
1394 class PokemonFormPokeathlonStat(TableBase):
1395 u"""A Pokémon form's performance in one Pokéathlon stat."""
1396 __tablename__ = 'pokemon_form_pokeathlon_stats'
1397 pokemon_form_id = Column(Integer, ForeignKey('pokemon_forms.id'), primary_key=True, nullable=False, autoincrement=False,
1398 info=dict(description=u'The ID of the Pokémon form.'))
1399 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False, autoincrement=False,
1400 info=dict(description=u'The ID of the Pokéathlon stat.'))
1401 minimum_stat = Column(Integer, nullable=False, autoincrement=False,
1402 info=dict(description=u'The minimum value for this stat for this Pokémon form.'))
1403 base_stat = Column(Integer, nullable=False, autoincrement=False,
1404 info=dict(description=u'The default value for this stat for this Pokémon form.'))
1405 maximum_stat = Column(Integer, nullable=False, autoincrement=False,
1406 info=dict(description=u'The maximum value for this stat for this Pokémon form.'))
1407
1408 class PokemonGameIndex(TableBase):
1409 u"""The number of a Pokémon a game uses internally
1410 """
1411 __tablename__ = 'pokemon_game_indices'
1412 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False,
1413 info=dict(description=u"Database ID of the Pokémon"))
1414 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
1415 info=dict(description=u"Database ID of the generation"))
1416 game_index = Column(Integer, nullable=False,
1417 info=dict(description=u"Internal ID the generation's games use for the Pokémon"))
1418
1419 class PokemonHabitat(TableBase):
1420 u"""The habitat of a Pokémon, as given in the FireRed/LeafGreen version Pokédex
1421 """
1422 __tablename__ = 'pokemon_habitats'
1423 __singlename__ = 'pokemon_habitat'
1424 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1425 info=dict(description=u"A numeric ID"))
1426 identifier = Column(Unicode(16), nullable=False,
1427 info=dict(description=u"An identifier", format='identifier'))
1428
1429 create_translation_table('pokemon_habitat_names', PokemonHabitat, 'names',
1430 relation_lazy='joined',
1431 name = Column(Unicode(16), nullable=False, index=True,
1432 info=dict(description="The name", format='plaintext', official=True)),
1433 )
1434
1435 class PokemonItem(TableBase):
1436 u"""Record of an item a Pokémon can hold in the wild
1437 """
1438 __tablename__ = 'pokemon_items'
1439 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1440 info=dict(description=u"ID of the Pokémon"))
1441 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
1442 info=dict(description=u"ID of the version this applies to"))
1443 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, nullable=False, autoincrement=False,
1444 info=dict(description=u"ID of the item"))
1445 rarity = Column(Integer, nullable=False,
1446 info=dict(description=u"Chance of the Pokémon holding the item, in percent"))
1447
1448 class PokemonMove(TableBase):
1449 u"""Record of a move a Pokémon can learn
1450 """
1451 __tablename__ = 'pokemon_moves'
1452 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, index=True,
1453 info=dict(description=u"ID of the Pokémon"))
1454 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, index=True,
1455 info=dict(description=u"ID of the version group this applies to"))
1456 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False, index=True,
1457 info=dict(description=u"ID of the move"))
1458 pokemon_move_method_id = Column(Integer, ForeignKey('pokemon_move_methods.id'), nullable=False, index=True,
1459 info=dict(description=u"ID of the method this move is learned by"))
1460 level = Column(Integer, nullable=True, index=True,
1461 info=dict(description=u"Level the move is learned at, if applicable"))
1462 order = Column(Integer, nullable=True,
1463 info=dict(description=u"A sort key to produce the correct ordering when all else is equal")) # XXX: This needs a better description
1464
1465 __table_args__ = (
1466 PrimaryKeyConstraint('pokemon_id', 'version_group_id', 'move_id', 'pokemon_move_method_id', 'level'),
1467 {},
1468 )
1469
1470 class PokemonMoveMethod(TableBase):
1471 u"""A method a move can be learned by, such as "Level up" or "Tutor".
1472 """
1473 __tablename__ = 'pokemon_move_methods'
1474 __singlename__ = 'pokemon_move_method'
1475 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1476 info=dict(description=u"A numeric ID"))
1477 identifier = Column(Unicode(64), nullable=False,
1478 info=dict(description=u"An identifier", format='identifier'))
1479
1480 create_translation_table('pokemon_move_method_prose', PokemonMoveMethod, 'prose',
1481 relation_lazy='joined',
1482 name = Column(Unicode(64), nullable=False, index=True,
1483 info=dict(description="The name", format='plaintext', official=False)),
1484 description = Column(Unicode(255), nullable=False,
1485 info=dict(description=u"A detailed description of how the method works", format='plaintext')),
1486 )
1487
1488 class PokemonShape(TableBase):
1489 u"""The shape of a Pokémon's body, as used in generation IV Pokédexes.
1490 """
1491 __tablename__ = 'pokemon_shapes'
1492 __singlename__ = 'pokemon_shape'
1493 id = Column(Integer, primary_key=True, nullable=False,
1494 info=dict(description=u"A numeric ID"))
1495 identifier = Column(Unicode(24), nullable=False,
1496 info=dict(description=u"An identifier", format='identifier'))
1497
1498 create_translation_table('pokemon_shape_prose', PokemonShape, 'prose',
1499 relation_lazy='joined',
1500 name = Column(Unicode(24), nullable=False, index=True,
1501 info=dict(description="The name", format='plaintext', official=False)),
1502 awesome_name = Column(Unicode(16), nullable=False,
1503 info=dict(description=u"A splendiferous name of the body shape", format='plaintext')),
1504 )
1505
1506 class PokemonStat(TableBase):
1507 u"""A stat value of a Pokémon
1508 """
1509 __tablename__ = 'pokemon_stats'
1510 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1511 info=dict(description=u"ID of the Pokémon"))
1512 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False,
1513 info=dict(description=u"ID of the stat"))
1514 base_stat = Column(Integer, nullable=False,
1515 info=dict(description=u"The base stat"))
1516 effort = Column(Integer, nullable=False,
1517 info=dict(description=u"The effort increase in this stat gained when this Pokémon is defeated"))
1518
1519 class PokemonType(TableBase):
1520 u"""Maps a type to a Pokémon. Each Pokémon has 1 or 2 types.
1521 """
1522 __tablename__ = 'pokemon_types'
1523 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1524 info=dict(description=u"ID of the Pokémon"))
1525 type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
1526 info=dict(description=u"ID of the type"))
1527 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1528 info=dict(description=u"The type's slot, 1 or 2, used to sort types if there are two of them"))
1529
1530 class Region(TableBase):
1531 u"""Major areas of the world: Kanto, Johto, etc.
1532 """
1533 __tablename__ = 'regions'
1534 __singlename__ = 'region'
1535 id = Column(Integer, primary_key=True, nullable=False,
1536 info=dict(description=u"A numeric ID"))
1537 identifier = Column(Unicode(16), nullable=False,
1538 info=dict(description=u"An identifier", format='identifier'))
1539
1540 create_translation_table('region_names', Region, 'names',
1541 relation_lazy='joined',
1542 name = Column(Unicode(16), nullable=False, index=True,
1543 info=dict(description="The name", format='plaintext', official=True)),
1544 )
1545
1546 class Stat(TableBase):
1547 u"""A Stat, such as Attack or Speed
1548 """
1549 __tablename__ = 'stats'
1550 __singlename__ = 'stat'
1551 id = Column(Integer, primary_key=True, nullable=False,
1552 info=dict(description=u"A numeric ID"))
1553 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True,
1554 info=dict(description=u"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
1555 identifier = Column(Unicode(16), nullable=False,
1556 info=dict(description=u"An identifier", format='identifier'))
1557 is_battle_only = Column(Boolean, nullable=False,
1558 info=dict(description=u"Whether this stat only exists within a battle"))
1559
1560 create_translation_table('stat_names', Stat, 'names',
1561 relation_lazy='joined',
1562 name = Column(Unicode(16), nullable=False, index=True,
1563 info=dict(description="The name", format='plaintext', official=True)),
1564 )
1565
1566 class StatHint(TableBase):
1567 u"""Flavor text for genes that appears in a Pokémon's summary. Sometimes
1568 called "characteristics".
1569 """
1570 __tablename__ = 'stat_hints'
1571 __singlename__ = 'stat_hint'
1572 id = Column(Integer, primary_key=True, nullable=False,
1573 info=dict(description=u"A numeric ID"))
1574 stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
1575 info=dict(description=u"ID of the highest stat"))
1576 gene_mod_5 = Column(Integer, nullable=False, index=True,
1577 info=dict(description=u"Value of the highest stat modulo 5"))
1578
1579 create_translation_table('stat_hint_names', StatHint, 'names',
1580 relation_lazy='joined',
1581 message = Column(Unicode(24), nullable=False, index=True,
1582 info=dict(description=u"The text displayed", official=True, format='plaintext')),
1583 )
1584
1585 class SuperContestCombo(TableBase):
1586 u"""Combo of two moves in a Super Contest.
1587 """
1588 __tablename__ = 'super_contest_combos'
1589 first_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
1590 info=dict(description=u"The ID of the first move in the combo."))
1591 second_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
1592 info=dict(description=u"The ID of the second and last move."))
1593
1594 class SuperContestEffect(TableBase):
1595 u"""An effect a move can have when used in the Super Contest
1596 """
1597 __tablename__ = 'super_contest_effects'
1598 __singlename__ = 'super_contest_effect'
1599 id = Column(Integer, primary_key=True, nullable=False,
1600 info=dict(description=u"This effect's unique ID."))
1601 appeal = Column(SmallInteger, nullable=False,
1602 info=dict(description=u"The number of hearts the user gains."))
1603
1604 create_translation_table('super_contest_effect_prose', SuperContestEffect, 'prose',
1605 flavor_text = Column(Unicode(64), nullable=False,
1606 info=dict(description=u"A description of the effect.", format='plaintext', official=True)),
1607 )
1608
1609 class Type(TableBase):
1610 u"""Any of the elemental types Pokémon and moves can have."""
1611 __tablename__ = 'types'
1612 __singlename__ = 'type'
1613 id = Column(Integer, primary_key=True, nullable=False,
1614 info=dict(description=u"A unique ID for this type."))
1615 identifier = Column(Unicode(12), nullable=False,
1616 info=dict(description=u"An identifier", format='identifier'))
1617 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
1618 info=dict(description=u"The ID of the generation this type first appeared in."))
1619 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True,
1620 info=dict(description=u"The ID of the damage class this type's moves had before Generation IV, null if not applicable (e.g. ???)."))
1621
1622 create_translation_table('type_names', Type, 'names',
1623 relation_lazy='joined',
1624 name = Column(Unicode(12), nullable=False, index=True,
1625 info=dict(description="The name", format='plaintext', official=True)),
1626 )
1627
1628 class TypeEfficacy(TableBase):
1629 u"""The damage multiplier used when a move of a particular type damages a
1630 Pokémon of a particular other type.
1631 """
1632 __tablename__ = 'type_efficacy'
1633 damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1634 info=dict(description=u"The ID of the damaging type."))
1635 target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1636 info=dict(description=u"The ID of the defending Pokémon's type."))
1637 damage_factor = Column(Integer, nullable=False,
1638 info=dict(description=u"The multiplier, as a percentage of damage inflicted."))
1639
1640 class Version(TableBase):
1641 u"""An individual main-series Pokémon game."""
1642 __tablename__ = 'versions'
1643 __singlename__ = 'version'
1644 id = Column(Integer, primary_key=True, nullable=False,
1645 info=dict(description=u"A unique ID for this version."))
1646 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
1647 info=dict(description=u"The ID of the version group this game belongs to."))
1648 identifier = Column(Unicode(32), nullable=False,
1649 info=dict(description=u'And identifier', format='identifier'))
1650
1651 create_translation_table('version_names', Version, 'names',
1652 relation_lazy='joined',
1653 name = Column(Unicode(32), nullable=False, index=True,
1654 info=dict(description="The name", format='plaintext', official=True)),
1655 )
1656
1657 class VersionGroup(TableBase):
1658 u"""A group of versions, containing either two paired versions (such as Red
1659 and Blue) or a single game (such as Yellow.)
1660 """
1661 __tablename__ = 'version_groups'
1662 id = Column(Integer, primary_key=True, nullable=False,
1663 info=dict(description=u"This version group's unique ID."))
1664 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
1665 info=dict(description=u"The ID of the generation the games in this group belong to."))
1666 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), nullable=False,
1667 info=dict(description=u"The ID of the regional Pokédex used in this version group."))
1668
1669 class VersionGroupRegion(TableBase):
1670 u"""Maps a version group to a region that appears in it."""
1671 __tablename__ = 'version_group_regions'
1672 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
1673 info=dict(description=u"The ID of the version group."))
1674 region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
1675 info=dict(description=u"The ID of the region."))
1676
1677 ### Relations down here, to avoid ordering problems
1678 Ability.changelog = relation(AbilityChangelog,
1679 order_by=AbilityChangelog.changed_in_version_group_id.desc(),
1680 backref='ability',
1681 )
1682 Ability.flavor_text = relation(AbilityFlavorText, order_by=AbilityFlavorText.version_group_id, backref='ability')
1683 Ability.generation = relation(Generation, backref='abilities')
1684
1685 AbilityChangelog.changed_in = relation(VersionGroup, backref='ability_changelog')
1686
1687 AbilityFlavorText.version_group = relation(VersionGroup)
1688 AbilityFlavorText.language = relation(Language)
1689
1690 Berry.berry_firmness = relation(BerryFirmness, backref='berries')
1691 Berry.firmness = association_proxy('berry_firmness', 'name')
1692 Berry.flavors = relation(BerryFlavor, order_by=BerryFlavor.contest_type_id, backref='berry')
1693 Berry.natural_gift_type = relation(Type)
1694
1695 BerryFlavor.contest_type = relation(ContestType)
1696
1697 ContestCombo.first = relation(Move, primaryjoin=ContestCombo.first_move_id==Move.id,
1698 backref='contest_combo_first')
1699 ContestCombo.second = relation(Move, primaryjoin=ContestCombo.second_move_id==Move.id,
1700 backref='contest_combo_second')
1701
1702 Encounter.location_area = relation(LocationArea, backref='encounters')
1703 Encounter.pokemon = relation(Pokemon, backref='encounters')
1704 Encounter.version = relation(Version, backref='encounters')
1705 Encounter.slot = relation(EncounterSlot, backref='encounters')
1706
1707 EncounterConditionValue.condition = relation(EncounterCondition, backref='values')
1708
1709 Encounter.condition_value_map = relation(EncounterConditionValueMap, backref='encounter')
1710 Encounter.condition_values = association_proxy('condition_value_map', 'condition_value')
1711 EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
1712 backref='encounter_map')
1713
1714 EncounterSlot.terrain = relation(EncounterTerrain, backref='slots')
1715 EncounterSlot.version_group = relation(VersionGroup)
1716
1717 EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
1718 EvolutionChain.baby_trigger_item = relation(Item, backref='evolution_chains')
1719
1720 Experience.growth_rate = relation(GrowthRate, backref='experience_table')
1721
1722 Generation.canonical_pokedex = relation(Pokedex, backref='canonical_for_generation')
1723 Generation.versions = relation(Version, secondary=VersionGroup.__table__)
1724 Generation.main_region = relation(Region)
1725
1726 GrowthRate.max_experience_obj = relation(Experience, primaryjoin=and_(Experience.growth_rate_id == GrowthRate.id, Experience.level == 100), uselist=False)
1727 GrowthRate.max_experience = association_proxy('max_experience_obj', 'experience')
1728
1729 Item.berry = relation(Berry, uselist=False, backref='item')
1730 Item.flags = relation(ItemFlag, secondary=ItemFlagMap.__table__)
1731 Item.flavor_text = relation(ItemFlavorText, order_by=ItemFlavorText.version_group_id.asc(), backref='item')
1732 Item.fling_effect = relation(ItemFlingEffect, backref='items')
1733 Item.machines = relation(Machine, order_by=Machine.version_group_id.asc())
1734 Item.category = relation(ItemCategory)
1735 Item.pocket = association_proxy('category', 'pocket')
1736
1737 ItemCategory.items = relation(Item, order_by=Item.identifier)
1738 ItemCategory.pocket = relation(ItemPocket)
1739
1740 ItemFlavorText.version_group = relation(VersionGroup)
1741 ItemFlavorText.language = relation(Language)
1742
1743 ItemGameIndex.item = relation(Item, backref='game_indices')
1744 ItemGameIndex.generation = relation(Generation)
1745
1746 ItemPocket.categories = relation(ItemCategory, order_by=ItemCategory.identifier)
1747
1748 Location.region = relation(Region, backref='locations')
1749
1750 LocationArea.location = relation(Location, backref='areas')
1751
1752 LocationGameIndex.location = relation(Location, backref='game_indices')
1753 LocationGameIndex.generation = relation(Generation)
1754
1755 Machine.item = relation(Item)
1756 Machine.version_group = relation(VersionGroup)
1757
1758 Move.changelog = relation(MoveChangelog,
1759 order_by=MoveChangelog.changed_in_version_group_id.desc(),
1760 backref='move',
1761 )
1762 Move.contest_effect = relation(ContestEffect, backref='moves')
1763 Move.contest_combo_next = association_proxy('contest_combo_first', 'second')
1764 Move.contest_combo_prev = association_proxy('contest_combo_second', 'first')
1765 Move.contest_type = relation(ContestType, backref='moves')
1766 Move.damage_class = relation(MoveDamageClass, backref='moves')
1767 Move.flags = association_proxy('move_flags', 'flag')
1768 Move.flavor_text = relation(MoveFlavorText, order_by=MoveFlavorText.version_group_id, backref='move')
1769 Move.generation = relation(Generation, backref='moves')
1770 Move.machines = relation(Machine, backref='move')
1771 Move.meta = relation(MoveMeta, uselist=False, backref='move')
1772 Move.meta_stat_changes = relation(MoveMetaStatChange)
1773 Move.move_effect = relation(MoveEffect, backref='moves')
1774 Move.move_flags = relation(MoveFlag, backref='move')
1775 Move.super_contest_effect = relation(SuperContestEffect, backref='moves')
1776 Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
1777 Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
1778 Move.target = relation(MoveTarget, backref='moves')
1779 Move.type = relation(Type, backref='moves')
1780
1781 Move.effect = markdown.MoveEffectProperty('effect')
1782 Move.effect_map = markdown.MoveEffectProperty('effect_map')
1783 Move.short_effect = markdown.MoveEffectProperty('short_effect')
1784 Move.short_effect_map = markdown.MoveEffectProperty('short_effect_map')
1785
1786 MoveChangelog.changed_in = relation(VersionGroup, backref='move_changelog')
1787 MoveChangelog.move_effect = relation(MoveEffect, backref='move_changelog')
1788 MoveChangelog.type = relation(Type, backref='move_changelog')
1789
1790 MoveChangelog.effect = markdown.MoveEffectProperty('effect')
1791 MoveChangelog.effect_map = markdown.MoveEffectProperty('effect_map')
1792 MoveChangelog.short_effect = markdown.MoveEffectProperty('short_effect')
1793 MoveChangelog.short_effect_map = markdown.MoveEffectProperty('short_effect_map')
1794
1795 MoveEffect.category_map = relation(MoveEffectCategoryMap)
1796 MoveEffect.categories = association_proxy('category_map', 'category')
1797 MoveEffect.changelog = relation(MoveEffectChangelog,
1798 order_by=MoveEffectChangelog.changed_in_version_group_id.desc(),
1799 backref='move_effect',
1800 )
1801 MoveEffectCategoryMap.category = relation(MoveEffectCategory)
1802
1803 MoveEffectChangelog.changed_in = relation(VersionGroup, backref='move_effect_changelog')
1804
1805 MoveFlag.flag = relation(MoveFlagType)
1806
1807 MoveFlavorText.version_group = relation(VersionGroup)
1808 MoveFlavorText.language = relation(Language)
1809
1810 MoveMeta.category = relation(MoveMetaCategory, backref='move_meta')
1811 MoveMeta.ailment = relation(MoveMetaAilment, backref='move_meta')
1812
1813 MoveMetaStatChange.stat = relation(Stat, backref='move_meta_stat_changes')
1814
1815 Nature.decreased_stat = relation(Stat, primaryjoin=Nature.decreased_stat_id==Stat.id,
1816 backref='decreasing_natures')
1817 Nature.increased_stat = relation(Stat, primaryjoin=Nature.increased_stat_id==Stat.id,
1818 backref='increasing_natures')
1819 Nature.hates_flavor = relation(ContestType, primaryjoin=Nature.hates_flavor_id==ContestType.id,
1820 backref='hating_natures')
1821 Nature.likes_flavor = relation(ContestType, primaryjoin=Nature.likes_flavor_id==ContestType.id,
1822 backref='liking_natures')
1823 Nature.battle_style_preferences = relation(NatureBattleStylePreference,
1824 order_by=NatureBattleStylePreference.move_battle_style_id,
1825 backref='nature')
1826 Nature.pokeathlon_effects = relation(NaturePokeathlonStat, order_by=NaturePokeathlonStat.pokeathlon_stat_id)
1827
1828 NatureBattleStylePreference.battle_style = relation(MoveBattleStyle, backref='nature_preferences')
1829
1830 NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat, backref='nature_effects')
1831
1832 Pokedex.region = relation(Region, backref='pokedexes')
1833 Pokedex.version_groups = relation(VersionGroup, order_by=VersionGroup.id, backref='pokedex')
1834
1835 Pokemon.all_abilities = relation(Ability,
1836 secondary=PokemonAbility.__table__,
1837 order_by=PokemonAbility.slot,
1838 backref=backref('all_pokemon',
1839 order_by=Pokemon.order,
1840 ),
1841 )
1842 Pokemon.abilities = relation(Ability,
1843 secondary=PokemonAbility.__table__,
1844 primaryjoin=and_(
1845 Pokemon.id == PokemonAbility.pokemon_id,
1846 PokemonAbility.is_dream == False,
1847 ),
1848 order_by=PokemonAbility.slot,
1849 backref=backref('pokemon',
1850 order_by=Pokemon.order,
1851 ),
1852 )
1853 Pokemon.dream_ability = relation(Ability,
1854 secondary=PokemonAbility.__table__,
1855 primaryjoin=and_(
1856 Pokemon.id == PokemonAbility.pokemon_id,
1857 PokemonAbility.is_dream == True,
1858 ),
1859 uselist=False,
1860 backref=backref('dream_pokemon',
1861 order_by=Pokemon.order,
1862 ),
1863 )
1864 Pokemon.pokemon_color = relation(PokemonColor, backref='pokemon')
1865 Pokemon.color = association_proxy('pokemon_color', 'name')
1866 Pokemon.dex_numbers = relation(PokemonDexNumber, order_by=PokemonDexNumber.pokedex_id.asc(), backref='pokemon')
1867 Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
1868 order_by=PokemonEggGroup.egg_group_id,
1869 backref=backref('pokemon', order_by=Pokemon.order))
1870 Pokemon.evolution_chain = relation(EvolutionChain, backref=backref('pokemon', order_by=Pokemon.order))
1871 Pokemon.child_pokemon = relation(Pokemon,
1872 primaryjoin=Pokemon.id==PokemonEvolution.from_pokemon_id,
1873 secondary=PokemonEvolution.__table__,
1874 secondaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
1875 backref=backref('parent_pokemon', uselist=False),
1876 )
1877 Pokemon.flavor_text = relation(PokemonFlavorText, order_by=PokemonFlavorText.version_id.asc(), backref='pokemon')
1878 Pokemon.forms = relation(PokemonForm, primaryjoin=Pokemon.id==PokemonForm.form_base_pokemon_id,
1879 order_by=(PokemonForm.order.asc(), PokemonForm.identifier.asc()))
1880 Pokemon.default_form = relation(PokemonForm,
1881 primaryjoin=and_(Pokemon.id==PokemonForm.form_base_pokemon_id, PokemonForm.is_default==True),
1882 uselist=False,
1883 )
1884 Pokemon.pokemon_habitat = relation(PokemonHabitat, backref='pokemon')
1885 Pokemon.habitat = association_proxy('pokemon_habitat', 'name')
1886 Pokemon.items = relation(PokemonItem, backref='pokemon')
1887 Pokemon.generation = relation(Generation, backref='pokemon')
1888 Pokemon.shape = relation(PokemonShape, backref='pokemon')
1889 Pokemon.stats = relation(PokemonStat, backref='pokemon', order_by=PokemonStat.stat_id.asc())
1890 Pokemon.types = relation(Type,
1891 secondary=PokemonType.__table__,
1892 order_by=PokemonType.slot.asc(),
1893 backref=backref('pokemon', order_by=Pokemon.order),
1894 )
1895
1896 PokemonDexNumber.pokedex = relation(Pokedex)
1897
1898 PokemonEvolution.from_pokemon = relation(Pokemon,
1899 primaryjoin=PokemonEvolution.from_pokemon_id==Pokemon.id,
1900 backref='child_evolutions',
1901 )
1902 PokemonEvolution.to_pokemon = relation(Pokemon,
1903 primaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
1904 backref=backref('parent_evolution', uselist=False),
1905 )
1906 PokemonEvolution.child_evolutions = relation(PokemonEvolution,
1907 primaryjoin=PokemonEvolution.from_pokemon_id==PokemonEvolution.to_pokemon_id,
1908 foreign_keys=[PokemonEvolution.to_pokemon_id],
1909 backref=backref('parent_evolution',
1910 remote_side=[PokemonEvolution.from_pokemon_id],
1911 uselist=False,
1912 ),
1913 )
1914 PokemonEvolution.trigger = relation(EvolutionTrigger, backref='evolutions')
1915 PokemonEvolution.trigger_item = relation(Item,
1916 primaryjoin=PokemonEvolution.trigger_item_id==Item.id,
1917 backref='triggered_evolutions',
1918 )
1919 PokemonEvolution.held_item = relation(Item,
1920 primaryjoin=PokemonEvolution.held_item_id==Item.id,
1921 backref='required_for_evolutions',
1922 )
1923 PokemonEvolution.location = relation(Location, backref='triggered_evolutions')
1924 PokemonEvolution.known_move = relation(Move, backref='triggered_evolutions')
1925 PokemonEvolution.party_pokemon = relation(Pokemon,
1926 primaryjoin=PokemonEvolution.party_pokemon_id==Pokemon.id,
1927 backref='triggered_evolutions',
1928 )
1929 PokemonEvolution.trade_pokemon = relation(Pokemon,
1930 primaryjoin=PokemonEvolution.trade_pokemon_id==Pokemon.id,
1931 )
1932
1933 PokemonFlavorText.version = relation(Version)
1934 PokemonFlavorText.language = relation(Language)
1935
1936 PokemonForm.form_base_pokemon = relation(Pokemon, primaryjoin=PokemonForm.form_base_pokemon_id==Pokemon.id)
1937 PokemonForm.unique_pokemon = relation(Pokemon, backref=backref('unique_form', uselist=False),
1938 primaryjoin=PokemonForm.unique_pokemon_id==Pokemon.id)
1939 PokemonForm.version_group = relation(VersionGroup)
1940 PokemonForm.form_group = association_proxy('form_base_pokemon', 'form_group')
1941 PokemonForm.pokeathlon_stats = relation(PokemonFormPokeathlonStat,
1942 order_by=PokemonFormPokeathlonStat.pokeathlon_stat_id,
1943 backref='pokemon_form')
1944
1945 PokemonFormGroup.pokemon = relation(Pokemon, backref=backref('form_group',
1946 uselist=False))
1947
1948 PokemonFormPokeathlonStat.pokeathlon_stat = relation(PokeathlonStat)
1949
1950 PokemonItem.item = relation(Item, backref='pokemon')
1951 PokemonItem.version = relation(Version)
1952
1953 PokemonMove.pokemon = relation(Pokemon, backref='pokemon_moves')
1954 PokemonMove.version_group = relation(VersionGroup)
1955 PokemonMove.machine = relation(Machine, backref='pokemon_moves',
1956 primaryjoin=and_(Machine.version_group_id==PokemonMove.version_group_id,
1957 Machine.move_id==PokemonMove.move_id),
1958 foreign_keys=[Machine.version_group_id, Machine.move_id],
1959 uselist=False)
1960 PokemonMove.move = relation(Move, backref='pokemon_moves')
1961 PokemonMove.method = relation(PokemonMoveMethod)
1962
1963 PokemonStat.stat = relation(Stat)
1964
1965 # This is technically a has-many; Generation.main_region_id -> Region.id
1966 Region.generation = relation(Generation, uselist=False)
1967 Region.version_group_regions = relation(VersionGroupRegion, backref='region',
1968 order_by='VersionGroupRegion.version_group_id')
1969 Region.version_groups = association_proxy('version_group_regions', 'version_group')
1970
1971 Stat.damage_class = relation(MoveDamageClass, backref='stats')
1972
1973 StatHint.stat = relation(Stat, backref='hints')
1974
1975 SuperContestCombo.first = relation(Move, primaryjoin=SuperContestCombo.first_move_id==Move.id,
1976 backref='super_contest_combo_first')
1977 SuperContestCombo.second = relation(Move, primaryjoin=SuperContestCombo.second_move_id==Move.id,
1978 backref='super_contest_combo_second')
1979
1980 Type.damage_efficacies = relation(TypeEfficacy,
1981 primaryjoin=Type.id
1982 ==TypeEfficacy.damage_type_id,
1983 backref='damage_type')
1984 Type.target_efficacies = relation(TypeEfficacy,
1985 primaryjoin=Type.id
1986 ==TypeEfficacy.target_type_id,
1987 backref='target_type')
1988
1989 Type.generation = relation(Generation, backref='types')
1990 Type.damage_class = relation(MoveDamageClass, backref='types')
1991
1992 Version.generation = association_proxy('version_group', 'generation')
1993
1994 VersionGroup.versions = relation(Version, order_by=Version.id, backref='version_group')
1995 VersionGroup.generation = relation(Generation, backref='version_groups')
1996 VersionGroup.version_group_regions = relation(VersionGroupRegion, backref='version_group')
1997 VersionGroup.regions = association_proxy('version_group_regions', 'region')