2278cb01854fb98a59d652f123dc5f67273a5de7
[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 EncounterTerrain(TableBase):
363 u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
364 """
365
366 __tablename__ = 'encounter_terrain'
367 __singlename__ = __tablename__
368 id = Column(Integer, primary_key=True, nullable=False,
369 info=dict(description="A unique ID for the terrain"))
370 identifier = Column(Unicode(64), nullable=False,
371 info=dict(description="An identifier", format='identifier'))
372
373 create_translation_table('encounter_terrain_prose', EncounterTerrain, 'prose',
374 name = Column(Unicode(64), nullable=False, index=True,
375 info=dict(description="The name", format='plaintext', official=False)),
376 )
377
378 class EncounterSlot(TableBase):
379 u"""An abstract "slot" within a terrain, associated with both some set of conditions and a rarity.
380
381 Note that there are two encounters per slot, so the rarities will only add
382 up to 50.
383 """
384
385 __tablename__ = 'encounter_slots'
386 id = Column(Integer, primary_key=True, nullable=False,
387 info=dict(description="A unique ID for this slot"))
388 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, autoincrement=False,
389 info=dict(description="The ID of the version group this slot is in"))
390 encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=False, nullable=False, autoincrement=False,
391 info=dict(description="The ID of the terrain"))
392 slot = Column(Integer, nullable=True,
393 info=dict(description="This slot's order for the location and terrain"))
394 rarity = Column(Integer, nullable=False,
395 info=dict(description="The chance of the encounter as a percentage"))
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
507 class ItemCategory(TableBase):
508 u"""An item category
509 """
510 # XXX: This is fanon, right?
511 __tablename__ = 'item_categories'
512 __singlename__ = 'item_category'
513 id = Column(Integer, primary_key=True, nullable=False,
514 info=dict(description="A numeric ID"))
515 pocket_id = Column(Integer, ForeignKey('item_pockets.id'), nullable=False,
516 info=dict(description="ID of the pocket these items go to"))
517 identifier = Column(Unicode(16), nullable=False,
518 info=dict(description="An identifier", format='identifier'))
519
520 create_translation_table('item_category_prose', ItemCategory, 'prose',
521 relation_lazy='joined',
522 name = Column(Unicode(16), nullable=False, index=True,
523 info=dict(description="The name", format='plaintext', official=False)),
524 )
525
526 class ItemFlag(TableBase):
527 u"""An item attribute such as "consumable" or "holdable".
528 """
529 __tablename__ = 'item_flags'
530 __singlename__ = 'item_flag'
531 id = Column(Integer, primary_key=True, nullable=False,
532 info=dict(description="A numeric ID"))
533 identifier = Column(Unicode(24), nullable=False,
534 info=dict(description="Identifier of the flag", format='identifier'))
535
536 create_translation_table('item_flag_prose', ItemFlag, 'prose',
537 name = Column(Unicode(24), nullable=False, index=True,
538 info=dict(description="The name", format='plaintext', official=False)),
539 description = Column(Unicode(64), nullable=False,
540 info=dict(description="Short description of the flag", format='plaintext')),
541 )
542
543 class ItemFlagMap(TableBase):
544 u"""Maps an item flag to its item.
545 """
546 __tablename__ = 'item_flag_map'
547 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
548 info=dict(description="The ID of the item"))
549 item_flag_id = Column(Integer, ForeignKey('item_flags.id'), primary_key=True, autoincrement=False, nullable=False,
550 info=dict(description="The ID of the item flag"))
551
552 class ItemFlavorText(TableBase):
553 u"""An in-game description of an item
554 """
555 __tablename__ = 'item_flavor_text'
556 __singlename__ = 'item_flavor_text'
557 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
558 info=dict(description="The ID of the item"))
559 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False,
560 info=dict(description="ID of the version group that sports this text"))
561 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
562 info=dict(description="The language"))
563 flavor_text = Column(Unicode(255), nullable=False,
564 info=dict(description="The flavor text itself", official=True, format='gametext'))
565
566 class ItemFlingEffect(TableBase):
567 u"""An effect of the move Fling when used with a specific item
568 """
569 __tablename__ = 'item_fling_effects'
570 __singlename__ = 'item_fling_effect'
571 id = Column(Integer, primary_key=True, nullable=False,
572 info=dict(description="A numeric ID"))
573
574 create_translation_table('item_fling_effect_prose', ItemFlingEffect, 'prose',
575 effect = Column(Unicode(255), nullable=False,
576 info=dict(description="Description of the effect", format='plaintext')),
577 )
578
579 class ItemGameIndex(TableBase):
580 u"""The internal ID number a game uses for an item
581 """
582 __tablename__ = 'item_game_indices'
583 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
584 info=dict(description="The database ID of the item"))
585 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
586 info=dict(description="ID of the generation of games"))
587 game_index = Column(Integer, nullable=False,
588 info=dict(description="Internal ID of the item in the generation"))
589
590 class ItemPocket(TableBase):
591 u"""A pocket that categorizes items
592 """
593 __tablename__ = 'item_pockets'
594 __singlename__ = 'item_pocket'
595 id = Column(Integer, primary_key=True, nullable=False,
596 info=dict(description="A numeric ID"))
597 identifier = Column(Unicode(16), nullable=False,
598 info=dict(description="An identifier of this pocket", format='identifier'))
599
600 create_translation_table('item_pocket_names', ItemPocket, 'names',
601 relation_lazy='joined',
602 name = Column(Unicode(16), nullable=False, index=True,
603 info=dict(description="The name", format='plaintext', official=True)),
604 )
605
606 class Location(TableBase):
607 u"""A place in the Pokémon world
608 """
609 __tablename__ = 'locations'
610 __singlename__ = 'location'
611 id = Column(Integer, primary_key=True, nullable=False,
612 info=dict(description="A numeric ID"))
613 region_id = Column(Integer, ForeignKey('regions.id'),
614 info=dict(description="ID of the region this location is in"))
615 identifier = Column(Unicode(64), nullable=False,
616 info=dict(description="An identifier", format='identifier'))
617
618 create_translation_table('location_names', Location, 'names',
619 relation_lazy='joined',
620 name = Column(Unicode(64), nullable=False, index=True,
621 info=dict(description="The name", format='plaintext', official=True)),
622 )
623
624 class LocationArea(TableBase):
625 u"""A sub-area of a location
626 """
627 __tablename__ = 'location_areas'
628 __singlename__ = 'location_area'
629 id = Column(Integer, primary_key=True, nullable=False,
630 info=dict(description="A numeric ID"))
631 location_id = Column(Integer, ForeignKey('locations.id'), nullable=False,
632 info=dict(description="ID of the location this area is part of"))
633 game_index = Column(Integer, nullable=False,
634 info=dict(description="ID the games ude for this area"))
635 identifier = Column(Unicode(64), nullable=True,
636 info=dict(description="An identifier", format='identifier'))
637
638 create_translation_table('location_area_prose', LocationArea, 'prose',
639 relation_lazy='joined',
640 name = Column(Unicode(64), nullable=False, index=True,
641 info=dict(description="The name", format='plaintext', official=False)),
642 )
643
644 class LocationAreaEncounterRate(TableBase):
645 # XXX: What's this exactly? Someone add the docstring & revise the descriptions
646 __tablename__ = 'location_area_encounter_rates'
647 location_area_id = Column(Integer, ForeignKey('location_areas.id'), primary_key=True, nullable=False, autoincrement=False,
648 info=dict(description="ID of the area"))
649 encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=True, nullable=False, autoincrement=False,
650 info=dict(description="ID of the terrain"))
651 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, autoincrement=False,
652 info=dict(description="ID of the version"))
653 rate = Column(Integer, nullable=True,
654 info=dict(description="The encounter rate")) # units?
655
656 class LocationGameIndex(TableBase):
657 u"""IDs the games use internally for locations
658 """
659 __tablename__ = 'location_game_indices'
660 location_id = Column(Integer, ForeignKey('locations.id'), nullable=False, primary_key=True,
661 info=dict(description="Database ID of the locaion"))
662 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True,
663 info=dict(description="ID of the generation this entry to"))
664 game_index = Column(Integer, nullable=False,
665 info=dict(description="Internal game ID of the location"))
666
667 class Machine(TableBase):
668 u"""A TM or HM; numbered item that can teach a move to a Pokémon
669 """
670 __tablename__ = 'machines'
671 machine_number = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
672 info=dict(description="Number of the machine for TMs, or 100 + the munber for HMs"))
673 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
674 info=dict(description="Versions this entry applies to"))
675 item_id = Column(Integer, ForeignKey('items.id'), nullable=False,
676 info=dict(description="ID of the corresponding Item"))
677 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False,
678 info=dict(description="ID of the taught move"))
679
680 @property
681 def is_hm(self):
682 u"""True if this machine is a HM, False if it's a TM
683 """
684 return self.machine_number >= 100
685
686 class MoveBattleStyle(TableBase):
687 u"""A battle style of a move""" # XXX: Explain better
688 __tablename__ = 'move_battle_styles'
689 __singlename__ = 'move_battle_style'
690 id = Column(Integer, primary_key=True, nullable=False,
691 info=dict(description="A numeric ID"))
692 identifier = Column(Unicode(8), nullable=False,
693 info=dict(description="An identifier", format='identifier'))
694
695 create_translation_table('move_battle_style_prose', MoveBattleStyle, 'prose',
696 relation_lazy='joined',
697 name = Column(Unicode(8), nullable=False, index=True,
698 info=dict(description="The name", format='plaintext', official=False)),
699 )
700
701 class MoveEffectCategory(TableBase):
702 u"""Category of a move effect
703 """
704 __tablename__ = 'move_effect_categories'
705 __singlename__ = 'move_effect_category'
706 id = Column(Integer, primary_key=True, nullable=False,
707 info=dict(description="A numeric ID"))
708 identifier = Column(Unicode(64), nullable=False,
709 info=dict(description="An identifier", format='identifier'))
710 can_affect_user = Column(Boolean, nullable=False,
711 info=dict(description="Set if the user can be affected"))
712
713 create_translation_table('move_effect_category_prose', MoveEffectCategory, 'prose',
714 name = Column(Unicode(64), nullable=False, index=True,
715 info=dict(description="The name", format='plaintext', official=False)),
716 )
717
718 class MoveEffectCategoryMap(TableBase):
719 u"""Maps a move effect category to a move effect
720 """
721 __tablename__ = 'move_effect_category_map'
722 move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False,
723 info=dict(description="ID of the move effect"))
724 move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False,
725 info=dict(description="ID of the category"))
726 affects_user = Column(Boolean, primary_key=True, nullable=False,
727 info=dict(description="Set if the user is affected"))
728
729 class MoveDamageClass(TableBase):
730 u"""Any of the damage classes moves can have, i.e. physical, special, or non-damaging.
731 """
732 __tablename__ = 'move_damage_classes'
733 __singlename__ = 'move_damage_class'
734 id = Column(Integer, primary_key=True, nullable=False,
735 info=dict(description="A numeric ID"))
736 identifier = Column(Unicode(16), nullable=False,
737 info=dict(description="An identifier", format='identifier'))
738
739 create_translation_table('move_damage_class_prose', MoveDamageClass, 'prose',
740 relation_lazy='joined',
741 name = Column(Unicode(16), nullable=False, index=True,
742 info=dict(description="The name", format='plaintext', official=False)),
743 description = Column(Unicode(64), nullable=False,
744 info=dict(description="A description of the class", format='plaintext')),
745 )
746
747 class MoveEffect(TableBase):
748 u"""An effect of a move
749 """
750 __tablename__ = 'move_effects'
751 __singlename__ = 'move_effect'
752 id = Column(Integer, primary_key=True, nullable=False,
753 info=dict(description="A numeric ID"))
754
755 create_translation_table('move_effect_prose', MoveEffect, 'prose',
756 short_effect = Column(Unicode(256), nullable=False,
757 info=dict(description="A short summary of the effect", format='plaintext')),
758 effect = Column(Unicode(5120), nullable=False,
759 info=dict(description="A detailed description of the effect", format='plaintext')),
760 )
761
762 class MoveEffectChangelog(TableBase):
763 """History of changes to move effects across main game versions."""
764 __tablename__ = 'move_effect_changelog'
765 __singlename__ = 'move_effect_changelog'
766 id = Column(Integer, primary_key=True, nullable=False,
767 info=dict(description="A numeric ID"))
768 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
769 info=dict(description="The ID of the effect that changed"))
770 changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
771 info=dict(description="The ID of the version group in which the effect changed"))
772
773 __table_args__ = (
774 UniqueConstraint(effect_id, changed_in_version_group_id),
775 {},
776 )
777
778 create_translation_table('move_effect_changelog_prose', MoveEffectChangelog, 'prose',
779 effect = Column(markdown.MarkdownColumn(512), nullable=False,
780 info=dict(description="A description of the old behavior", format='markdown')),
781 )
782
783 class MoveFlag(TableBase):
784 u"""Maps a move flag to a move
785 """
786 # XXX: Other flags have a ___Flag class for the actual flag and ___FlagMap for the map,
787 # these, somewhat confusingly, have MoveFlagType and MoveFlag
788 __tablename__ = 'move_flags'
789 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
790 info=dict(description="ID of the move"))
791 move_flag_type_id = Column(Integer, ForeignKey('move_flag_types.id'), primary_key=True, nullable=False, autoincrement=False,
792 info=dict(description="ID of the flag"))
793
794 class MoveFlagType(TableBase):
795 u"""A Move attribute such as "snatchable" or "contact".
796 """
797 __tablename__ = 'move_flag_types'
798 __singlename__ = 'move_flag_type'
799 id = Column(Integer, primary_key=True, nullable=False,
800 info=dict(description="A numeric ID"))
801 identifier = Column(Unicode(32), nullable=False,
802 info=dict(description="A short identifier for the flag", format='identifier'))
803
804 create_translation_table('move_flag_type_prose', MoveFlagType, 'prose',
805 relation_lazy='joined',
806 name = Column(Unicode(32), nullable=False, index=True,
807 info=dict(description="The name", format='plaintext', official=False)),
808 description = Column(markdown.MarkdownColumn(128), nullable=False,
809 info=dict(description="A short description of the flag", format='markdown')),
810 )
811
812 class MoveFlavorText(TableBase):
813 u"""In-game description of a move
814 """
815 __tablename__ = 'move_flavor_text'
816 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
817 info=dict(description="ID of the move"))
818 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
819 info=dict(description="ID of the version group this text appears in"))
820 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
821 info=dict(description="The language"))
822 flavor_text = Column(Unicode(255), nullable=False,
823 info=dict(description="The flavor text", official=True, format='gametext'))
824
825 class MoveMeta(TableBase):
826 u"""Metadata for move effects, sorta-kinda ripped straight from the game"""
827 __tablename__ = 'move_meta'
828 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
829 info=dict(description="A numeric ID"))
830 meta_category_id = Column(Integer, ForeignKey('move_meta_categories.id'), nullable=False,
831 info=dict(description="ID of the move category"))
832 meta_ailment_id = Column(Integer, ForeignKey('move_meta_ailments.id'), nullable=False,
833 info=dict(description="ID of the caused ailment"))
834 min_hits = Column(Integer, nullable=True, index=True,
835 info=dict(description="Minimum number of hits per use"))
836 max_hits = Column(Integer, nullable=True, index=True,
837 info=dict(description="Maximum number of hits per use"))
838 min_turns = Column(Integer, nullable=True, index=True,
839 info=dict(description="Minimum number of turns the user is forced to use the move"))
840 max_turns = Column(Integer, nullable=True, index=True,
841 info=dict(description="Maximum number of turns the user is forced to use the move"))
842 recoil = Column(Integer, nullable=False, index=True,
843 info=dict(description="Recoil damage, in percent of damage done"))
844 healing = Column(Integer, nullable=False, index=True,
845 info=dict(description="Healing, in percent of user's max HP"))
846 crit_rate = Column(Integer, nullable=False, index=True,
847 info=dict(description="Critical hit rate bonus"))
848 ailment_chance = Column(Integer, nullable=False, index=True,
849 info=dict(description="Chance to cause an ailment, in percent"))
850 flinch_chance = Column(Integer, nullable=False, index=True,
851 info=dict(description="Chance to cause flinching, in percent"))
852 stat_chance = Column(Integer, nullable=False, index=True,
853 info=dict(description="Chance to cause a stat change, in percent"))
854
855 class MoveMetaAilment(TableBase):
856 u"""Common status ailments moves can inflict on a single Pokémon, including
857 major ailments like paralysis and minor ailments like trapping.
858 """
859 __tablename__ = 'move_meta_ailments'
860 __singlename__ = 'move_meta_ailment'
861 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
862 info=dict(description="A numeric ID"))
863 identifier = Column(Unicode(24), nullable=False,
864 info=dict(description="An identifier", format='identifier'))
865
866 create_translation_table('move_meta_ailment_names', MoveMetaAilment, 'names',
867 relation_lazy='joined',
868 name = Column(Unicode(24), nullable=False, index=True,
869 info=dict(description="The name", format='plaintext', official=True)),
870 )
871
872 class MoveMetaCategory(TableBase):
873 u"""Very general categories that loosely group move effects."""
874 __tablename__ = 'move_meta_categories'
875 __singlename__ = 'move_meta_category'
876 id = Column(Integer, primary_key=True, nullable=False,
877 info=dict(description="A numeric ID"))
878
879 create_translation_table('move_meta_category_prose', MoveMetaCategory, 'prose',
880 relation_lazy='joined',
881 description = Column(Unicode(64), nullable=False,
882 info=dict(description="A description of the category", format="plaintext", official=False)),
883 )
884
885 class MoveMetaStatChange(TableBase):
886 u"""Stat changes moves (may) make."""
887 __tablename__ = 'move_meta_stat_changes'
888 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
889 info=dict(description="ID of the move"))
890 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False,
891 info=dict(description="ID of the stat"))
892 change = Column(Integer, nullable=False, index=True,
893 info=dict(description="Amount of increase/decrease, in stages"))
894
895 class MoveTarget(TableBase):
896 u"""Targetting or "range" of a move, e.g. "Affects all opponents" or "Affects user".
897 """
898 __tablename__ = 'move_targets'
899 __singlename__ = 'move_target'
900 id = Column(Integer, primary_key=True, nullable=False,
901 info=dict(description="A numeric ID"))
902 identifier = Column(Unicode(32), nullable=False,
903 info=dict(description="An identifier", format='identifier'))
904
905 create_translation_table('move_target_prose', MoveTarget, 'prose',
906 relation_lazy='joined',
907 name = Column(Unicode(32), nullable=False, index=True,
908 info=dict(description="The name", format='plaintext', official=False)),
909 description = Column(Unicode(128), nullable=False,
910 info=dict(description="A description", format='plaintext')),
911 )
912
913 class Move(TableBase):
914 u"""A Move: technique or attack a Pokémon can learn to use
915 """
916 __tablename__ = 'moves'
917 __singlename__ = 'move'
918 id = Column(Integer, primary_key=True, nullable=False,
919 info=dict(description="A numeric ID"))
920 identifier = Column(Unicode(24), nullable=False,
921 info=dict(description="An identifier", format='identifier'))
922 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
923 info=dict(description="ID of the generation this move first appeared in"))
924 type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
925 info=dict(description="ID of the move's elemental type"))
926 power = Column(SmallInteger, nullable=False,
927 info=dict(description="Base power of the move"))
928 pp = Column(SmallInteger, nullable=True,
929 info=dict(description="Base PP (Power Points) of the move, nullable if not applicable (e.g. Struggle and Shadow moves)."))
930 accuracy = Column(SmallInteger, nullable=True,
931 info=dict(description="Accuracy of the move; NULL means it never misses"))
932 priority = Column(SmallInteger, nullable=False,
933 info=dict(description="The move's priority bracket"))
934 target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False,
935 info=dict(description="ID of the target (range) of the move"))
936 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False,
937 info=dict(description="ID of the damage class (physical/special) of the move"))
938 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
939 info=dict(description="ID of the move's effect"))
940 effect_chance = Column(Integer, nullable=True,
941 info=dict(description="The chance for a secondary effect. What this is a chance of is specified by the move's effect."))
942 contest_type_id = Column(Integer, ForeignKey('contest_types.id'), nullable=True,
943 info=dict(description="ID of the move's Contest type (e.g. cool or smart)"))
944 contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True,
945 info=dict(description="ID of the move's Contest effect"))
946 super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=True,
947 info=dict(description="ID of the move's Super Contest effect"))
948
949 create_translation_table('move_names', Move, 'names',
950 relation_lazy='joined',
951 name = Column(Unicode(24), nullable=False, index=True,
952 info=dict(description="The name", format='plaintext', official=True))
953 )
954
955
956 class MoveChangelog(TableBase):
957 """History of changes to moves across main game versions."""
958 __tablename__ = 'move_changelog'
959 __singlename__ = 'move_changelog'
960 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
961 info=dict(description="ID of the move that changed"))
962 changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
963 info=dict(description="ID of the version group in which the move changed"))
964 type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
965 info=dict(description="Prior type of the move, or NULL if unchanged"))
966 power = Column(SmallInteger, nullable=True,
967 info=dict(description="Prior base power of the move, or NULL if unchanged"))
968 pp = Column(SmallInteger, nullable=True,
969 info=dict(description="Prior base PP of the move, or NULL if unchanged"))
970 accuracy = Column(SmallInteger, nullable=True,
971 info=dict(description="Prior accuracy of the move, or NULL if unchanged"))
972 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=True,
973 info=dict(description="Prior ID of the effect, or NULL if unchanged"))
974 effect_chance = Column(Integer, nullable=True,
975 info=dict(description="Prior effect chance, or NULL if unchanged"))
976
977 class Nature(TableBase):
978 u"""A nature a Pokémon can have, such as Calm or Brave
979 """
980 __tablename__ = 'natures'
981 __singlename__ = 'nature'
982 id = Column(Integer, primary_key=True, nullable=False,
983 info=dict(description="A numeric ID"))
984 identifier = Column(Unicode(8), nullable=False,
985 info=dict(description="An identifier", format='identifier'))
986 decreased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
987 info=dict(description="ID of the stat that this nature decreases by 10% (if decreased_stat_id is the same, the effects cancel out)"))
988 increased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
989 info=dict(description="ID of the stat that this nature increases by 10% (if decreased_stat_id is the same, the effects cancel out)"))
990 hates_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False,
991 info=dict(description=u"ID of the Berry flavor the Pokémon hates (if likes_flavor_id is the same, the effects cancel out)"))
992 likes_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False,
993 info=dict(description=u"ID of the Berry flavor the Pokémon likes (if hates_flavor_id is the same, the effects cancel out)"))
994
995 @property
996 def is_neutral(self):
997 u"""Returns True iff this nature doesn't alter a Pokémon's stats,
998 bestow taste preferences, etc.
999 """
1000 return self.increased_stat_id == self.decreased_stat_id
1001
1002 create_translation_table('nature_names', Nature, 'names',
1003 relation_lazy='joined',
1004 name = Column(Unicode(8), nullable=False, index=True,
1005 info=dict(description="The name", format='plaintext', official=True)),
1006 )
1007
1008 class NatureBattleStylePreference(TableBase):
1009 u"""Battle Palace move preference
1010
1011 Specifies how likely a Pokémon with a specific Nature is to use a move of
1012 a particular battl style in Battle Palace or Battle Tent
1013 """
1014 __tablename__ = 'nature_battle_style_preferences'
1015 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
1016 info=dict(description=u"ID of the Pokémon's nature"))
1017 move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False,
1018 info=dict(description="ID of the battle style"))
1019 low_hp_preference = Column(Integer, nullable=False,
1020 info=dict(description=u"Chance of using the move, in percent, if HP is under ½"))
1021 high_hp_preference = Column(Integer, nullable=False,
1022 info=dict(description=u"Chance of using the move, in percent, if HP is over ½"))
1023
1024 class NaturePokeathlonStat(TableBase):
1025 u"""Specifies how a Nature affects a Pokéathlon stat
1026 """
1027 __tablename__ = 'nature_pokeathlon_stats'
1028 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
1029 info=dict(description="ID of the nature"))
1030 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False,
1031 info=dict(description="ID of the stat"))
1032 max_change = Column(Integer, nullable=False,
1033 info=dict(description="Maximum change"))
1034
1035 class PokeathlonStat(TableBase):
1036 u"""A Pokéathlon stat, such as "Stamina" or "Jump".
1037 """
1038 __tablename__ = 'pokeathlon_stats'
1039 __singlename__ = 'pokeathlon_stat'
1040 id = Column(Integer, primary_key=True, nullable=False,
1041 info=dict(description="A numeric ID"))
1042 identifier = Column(Unicode(8), nullable=False,
1043 info=dict(description="An identifier", format='identifier'))
1044
1045 create_translation_table('pokeathlon_stat_names', PokeathlonStat, 'names',
1046 name = Column(Unicode(8), nullable=False, index=True,
1047 info=dict(description="The name", format='plaintext', official=True)),
1048 )
1049
1050 class Pokedex(TableBase):
1051 u"""A collection of Pokémon species ordered in a particular way
1052 """
1053 __tablename__ = 'pokedexes'
1054 __singlename__ = 'pokedex'
1055 id = Column(Integer, primary_key=True, nullable=False,
1056 info=dict(description="A numeric ID"))
1057 region_id = Column(Integer, ForeignKey('regions.id'), nullable=True,
1058 info=dict(description=u"ID of the region this Pokédex is used in, or None if it's global"))
1059 identifier = Column(Unicode(16), nullable=False,
1060 info=dict(description=u"An identifier", format='identifier'))
1061
1062 create_translation_table('pokedex_prose', Pokedex, 'prose',
1063 relation_lazy='joined',
1064 name = Column(Unicode(16), nullable=False, index=True,
1065 info=dict(description="The name", format='plaintext', official=False)),
1066 description = Column(Unicode(512), nullable=False,
1067 info=dict(description=u"A longer description of the Pokédex", format='plaintext')),
1068 )
1069
1070 class Pokemon(TableBase):
1071 u"""A species of Pokémon. The core to this whole mess.
1072 """
1073 __tablename__ = 'pokemon'
1074 __singlename__ = 'pokemon'
1075 id = Column(Integer, primary_key=True, nullable=False,
1076 info=dict(description=u"A numeric ID"))
1077 identifier = Column(Unicode(20), nullable=False,
1078 info=dict(description=u"An identifier", format='identifier'))
1079 generation_id = Column(Integer, ForeignKey('generations.id'),
1080 info=dict(description=u"ID of the generation this species first appeared in"))
1081 evolution_chain_id = Column(Integer, ForeignKey('evolution_chains.id'),
1082 info=dict(description=u"ID of the species' evolution chain (a.k.a. family)"))
1083 height = Column(Integer, nullable=False,
1084 info=dict(description=u"The height of the Pokémon, in decimeters (tenths of a meter)"))
1085 weight = Column(Integer, nullable=False,
1086 info=dict(description=u"The weight of the Pokémon, in tenths of a kilogram (decigrams)"))
1087 color_id = Column(Integer, ForeignKey('pokemon_colors.id'), nullable=False,
1088 info=dict(description=u"ID of this Pokémon's Pokédex color, as used for a gimmick search function in the games."))
1089 pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=False,
1090 info=dict(description=u"ID of this Pokémon's body shape, as used for a gimmick search function in the games."))
1091 habitat_id = Column(Integer, ForeignKey('pokemon_habitats.id'), nullable=True,
1092 info=dict(description=u"ID of this Pokémon's habitat, as used for a gimmick search function in the games."))
1093 gender_rate = Column(Integer, nullable=False,
1094 info=dict(description=u"The chance of this Pokémon being female, in eighths; or -1 for genderless"))
1095 capture_rate = Column(Integer, nullable=False,
1096 info=dict(description=u"The base capture rate; up to 255"))
1097 base_experience = Column(Integer, nullable=False,
1098 info=dict(description=u"The base EXP gained when defeating this Pokémon")) # XXX: Is this correct?
1099 base_happiness = Column(Integer, nullable=False,
1100 info=dict(description=u"The tameness when caught by a normal ball"))
1101 is_baby = Column(Boolean, nullable=False,
1102 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."))
1103 hatch_counter = Column(Integer, nullable=False,
1104 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"))
1105 has_gender_differences = Column(Boolean, nullable=False,
1106 info=dict(description=u"Set iff the species exhibits enough sexual dimorphism to have separate sets of sprites in Gen IV and beyond."))
1107 order = Column(Integer, nullable=False, index=True,
1108 info=dict(description=u"Order for sorting. Almost national order, except families and forms are grouped together."))
1109
1110 ### Stuff to handle alternate Pokémon forms
1111
1112 @property
1113 def form(self):
1114 u"""Returns the Pokémon's form, using its default form as fallback."""
1115
1116 return self.unique_form or self.default_form
1117
1118 @property
1119 def is_base_form(self):
1120 u"""Returns True iff the Pokémon is the base form for its species,
1121 e.g. Land Shaymin.
1122 """
1123
1124 return self.unique_form is None or self.unique_form.is_default
1125
1126 @property
1127 def form_name(self):
1128 u"""Returns the Pokémon's form name if it represents a particular form
1129 and that form has a name, or None otherwise.
1130 """
1131
1132 # If self.unique_form is None, the short-circuit "and" will go ahead
1133 # and return that. Otherwise, it'll return the form's name, which may
1134 # also be None.
1135 return self.unique_form and self.unique_form.name
1136
1137 @property
1138 def full_name(self):
1139 u"""Returns the Pokémon's name, including its form if applicable."""
1140
1141 if self.form_name:
1142 return u'{0} {1}'.format(self.form_name, self.name)
1143 else:
1144 return self.name
1145
1146 @property
1147 def normal_form(self):
1148 u"""Returns the normal form for this Pokémon; i.e., this will return
1149 regular Deoxys when called on any Deoxys form.
1150 """
1151
1152 if self.unique_form:
1153 return self.unique_form.form_base_pokemon
1154 return self
1155
1156 ### Not forms!
1157
1158 def stat(self, stat_name):
1159 u"""Returns a PokemonStat record for the given stat name (or Stat row
1160 object). Uses the normal has-many machinery, so all the stats are
1161 effectively cached.
1162 """
1163 if isinstance(stat_name, Stat):
1164 stat_name = stat_name.name
1165
1166 for pokemon_stat in self.stats:
1167 if pokemon_stat.stat.name == stat_name:
1168 return pokemon_stat
1169
1170 raise KeyError(u'No stat named %s' % stat_name)
1171
1172 @property
1173 def better_damage_class(self):
1174 u"""Returns the MoveDamageClass that this Pokémon is best suited for,
1175 based on its attack stats.
1176
1177 If the attack stats are about equal (within 5), returns None. The
1178 value None, not the damage class called 'None'.
1179 """
1180 phys = self.stat(u'Attack')
1181 spec = self.stat(u'Special Attack')
1182
1183 diff = phys.base_stat - spec.base_stat
1184
1185 if diff > 5:
1186 return phys.stat.damage_class
1187 elif diff < -5:
1188 return spec.stat.damage_class
1189 else:
1190 return None
1191
1192 create_translation_table('pokemon_names', Pokemon, 'names',
1193 relation_lazy='joined',
1194 name = Column(Unicode(20), nullable=False, index=True,
1195 info=dict(description="The name", format='plaintext', official=True)),
1196 species = Column(Unicode(16), nullable=False,
1197 info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
1198 official=True, format='plaintext')),
1199 )
1200
1201 class PokemonAbility(TableBase):
1202 u"""Maps an ability to a Pokémon that can have it
1203 """
1204 __tablename__ = 'pokemon_abilities'
1205 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1206 info=dict(description=u"ID of the Pokémon"))
1207 ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
1208 info=dict(description=u"ID of the ability"))
1209 # XXX having both a method and a slot is kind of gross. "slot" is a
1210 # misnomer, anyway: duplicate abilities don't appear in slot 2.
1211 # Probably should replace that with "order".
1212 is_dream = Column(Boolean, nullable=False, index=True,
1213 info=dict(description=u"Whether this is a Dream World ability"))
1214 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1215 info=dict(description=u"The ability slot, i.e. 1 or 2 for gen. IV"))
1216
1217 class PokemonColor(TableBase):
1218 u"""The "Pokédex color" of a Pokémon species. Usually based on the Pokémon's color.
1219 """
1220 __tablename__ = 'pokemon_colors'
1221 __singlename__ = 'pokemon_color'
1222 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1223 info=dict(description=u"ID of the Pokémon"))
1224 identifier = Column(Unicode(6), nullable=False,
1225 info=dict(description=u"An identifier", format='identifier'))
1226
1227 create_translation_table('pokemon_color_names', PokemonColor, 'names',
1228 relation_lazy='joined',
1229 name = Column(Unicode(6), nullable=False, index=True,
1230 info=dict(description="The name", format='plaintext', official=True)),
1231 )
1232
1233 class PokemonDexNumber(TableBase):
1234 u"""The number of a Pokémon in a particular Pokédex (e.g. Jigglypuff is #138 in Hoenn's 'dex)
1235 """
1236 __tablename__ = 'pokemon_dex_numbers'
1237 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1238 info=dict(description=u"ID of the Pokémon"))
1239 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), primary_key=True, nullable=False, autoincrement=False,
1240 info=dict(description=u"ID of the Pokédex"))
1241 pokedex_number = Column(Integer, nullable=False,
1242 info=dict(description=u"Number of the Pokémon in that the Pokédex"))
1243
1244 class PokemonEggGroup(TableBase):
1245 u"""Maps an Egg group to a Pokémon; each Pokémon belongs to one or two egg groups
1246 """
1247 __tablename__ = 'pokemon_egg_groups'
1248 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1249 info=dict(description=u"ID of the Pokémon"))
1250 egg_group_id = Column(Integer, ForeignKey('egg_groups.id'), primary_key=True, nullable=False, autoincrement=False,
1251 info=dict(description=u"ID of the egg group"))
1252
1253 class PokemonEvolution(TableBase):
1254 u"""A required action ("trigger") and the conditions under which the trigger
1255 must occur to cause a Pokémon to evolve.
1256
1257 Any condition may be null if it does not apply for a particular Pokémon.
1258 """
1259 __tablename__ = 'pokemon_evolution'
1260 from_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False,
1261 info=dict(description=u"The ID of the pre-evolution Pokémon."))
1262 to_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1263 info=dict(description=u"The ID of the post-evolution Pokémon."))
1264 evolution_trigger_id = Column(Integer, ForeignKey('evolution_triggers.id'), nullable=False,
1265 info=dict(description=u"The ID of the evolution trigger."))
1266 trigger_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
1267 info=dict(description=u"The ID of the item that must be used on the Pokémon."))
1268 minimum_level = Column(Integer, nullable=True,
1269 info=dict(description=u"The minimum level for the Pokémon."))
1270 gender = Column(Enum('male', 'female', name='pokemon_evolution_gender'), nullable=True,
1271 info=dict(description=u"The Pokémon's required gender, or None if gender doesn't matter"))
1272 location_id = Column(Integer, ForeignKey('locations.id'), nullable=True,
1273 info=dict(description=u"The ID of the location the evolution must be triggered at."))
1274 held_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
1275 info=dict(description=u"The ID of the item the Pokémon must hold."))
1276 time_of_day = Column(Enum('day', 'night', name='pokemon_evolution_time_of_day'), nullable=True,
1277 info=dict(description=u"The required time of day."))
1278 known_move_id = Column(Integer, ForeignKey('moves.id'), nullable=True,
1279 info=dict(description=u"The ID of the move the Pokémon must know."))
1280 minimum_happiness = Column(Integer, nullable=True,
1281 info=dict(description=u"The minimum happiness value the Pokémon must have."))
1282 minimum_beauty = Column(Integer, nullable=True,
1283 info=dict(description=u"The minimum Beauty value the Pokémon must have."))
1284 relative_physical_stats = Column(Integer, nullable=True,
1285 info=dict(description=u"The required relation between the Pokémon's Attack and Defense stats, as sgn(atk-def)."))
1286 party_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True,
1287 info=dict(description=u"The ID of the Pokémon that must be present in the party."))
1288 trade_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True,
1289 info=dict(description=u"The ID of the Pokémon for which this Pokémon must be traded."))
1290
1291 class PokemonFlavorText(TableBase):
1292 u"""In-game Pokédex descrption of a Pokémon.
1293 """
1294 __tablename__ = 'pokemon_flavor_text'
1295 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1296 info=dict(description=u"ID of the Pokémon"))
1297 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
1298 info=dict(description=u"ID of the version that has this flavor text"))
1299 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
1300 info=dict(description="The language"))
1301 flavor_text = Column(Unicode(255), nullable=False,
1302 info=dict(description=u"ID of the version that has this flavor text", official=True, format='gametext'))
1303
1304 class PokemonForm(TableBase):
1305 u"""An individual form of a Pokémon.
1306
1307 Pokémon that do not have separate forms are still given a single row to
1308 represent their single form.
1309 """
1310 __tablename__ = 'pokemon_forms'
1311 __singlename__ = 'pokemon_form'
1312 id = Column(Integer, primary_key=True, nullable=False,
1313 info=dict(description=u'A unique ID for this form.'))
1314 identifier = Column(Unicode(16), nullable=True,
1315 info=dict(description=u"An identifier", format='identifier'))
1316 form_base_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
1317 info=dict(description=u'The ID of the base Pokémon for this form.'))
1318 unique_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), autoincrement=False,
1319 info=dict(description=u'The ID of a Pokémon that represents specifically this form, for Pokémon with functionally-different forms like Wormadam.'))
1320 introduced_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), autoincrement=False,
1321 info=dict(description=u'The ID of the version group in which this form first appeared.'))
1322 is_default = Column(Boolean, nullable=False,
1323 info=dict(description=u'Set for exactly one form used as the default for each species.'))
1324 order = Column(Integer, nullable=False, autoincrement=False,
1325 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.'))
1326
1327 @property
1328 def pokemon(self):
1329 u"""Returns the Pokémon for this form, using the form base as fallback.
1330 """
1331
1332 return self.unique_pokemon or self.form_base_pokemon
1333
1334 @property
1335 def full_name(self):
1336 u"""Returns the full name of this form, e.g. "Plant Cloak"."""
1337
1338 if not self.name:
1339 return None
1340 elif self.form_group and self.form_group.term:
1341 return u'{0} {1}'.format(self.name, self.form_group.term)
1342 else:
1343 return self.name
1344
1345 @property
1346 def pokemon_name(self):
1347 u"""Returns the name of this Pokémon with this form, e.g. "Plant
1348 Burmy".
1349 """
1350
1351 if self.name:
1352 return u'{0} {1}'.format(self.name, self.form_base_pokemon.name)
1353 else:
1354 return self.form_base_pokemon.name
1355
1356 create_translation_table('pokemon_form_names', PokemonForm, 'names',
1357 relation_lazy='joined',
1358 name = Column(Unicode(16), nullable=False, index=True,
1359 info=dict(description="The name", format='plaintext', official=True)),
1360 )
1361
1362 class PokemonFormGroup(TableBase):
1363 u"""Information about a Pokémon's forms as a group."""
1364 __tablename__ = 'pokemon_form_groups'
1365 __singlename__ = 'pokemon_form_group'
1366 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1367 info=dict(description=u"ID of the base form Pokémon"))
1368 is_battle_only = Column(Boolean, nullable=False,
1369 info=dict(description=u"Set iff the forms only change in battle"))
1370 # FIXME remooove
1371 PokemonFormGroup.id = PokemonFormGroup.pokemon_id
1372
1373 create_translation_table('pokemon_form_group_prose', PokemonFormGroup, 'prose',
1374 term = Column(Unicode(16), nullable=True,
1375 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')),
1376 description = Column(markdown.MarkdownColumn(1024), nullable=False,
1377 info=dict(description=u"Description of how the forms work", format='markdown')),
1378 )
1379
1380 class PokemonFormPokeathlonStat(TableBase):
1381 u"""A Pokémon form's performance in one Pokéathlon stat."""
1382 __tablename__ = 'pokemon_form_pokeathlon_stats'
1383 pokemon_form_id = Column(Integer, ForeignKey('pokemon_forms.id'), primary_key=True, nullable=False, autoincrement=False,
1384 info=dict(description=u'The ID of the Pokémon form.'))
1385 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False, autoincrement=False,
1386 info=dict(description=u'The ID of the Pokéathlon stat.'))
1387 minimum_stat = Column(Integer, nullable=False, autoincrement=False,
1388 info=dict(description=u'The minimum value for this stat for this Pokémon form.'))
1389 base_stat = Column(Integer, nullable=False, autoincrement=False,
1390 info=dict(description=u'The default value for this stat for this Pokémon form.'))
1391 maximum_stat = Column(Integer, nullable=False, autoincrement=False,
1392 info=dict(description=u'The maximum value for this stat for this Pokémon form.'))
1393
1394 class PokemonHabitat(TableBase):
1395 u"""The habitat of a Pokémon, as given in the FireRed/LeafGreen version Pokédex
1396 """
1397 __tablename__ = 'pokemon_habitats'
1398 __singlename__ = 'pokemon_habitat'
1399 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1400 info=dict(description=u"A numeric ID"))
1401 identifier = Column(Unicode(16), nullable=False,
1402 info=dict(description=u"An identifier", format='identifier'))
1403
1404 create_translation_table('pokemon_habitat_names', PokemonHabitat, 'names',
1405 relation_lazy='joined',
1406 name = Column(Unicode(16), nullable=False, index=True,
1407 info=dict(description="The name", format='plaintext', official=True)),
1408 )
1409
1410 class PokemonGameIndex(TableBase):
1411 u"""The number of a Pokémon a game uses internally
1412 """
1413 __tablename__ = 'pokemon_game_indices'
1414 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False,
1415 info=dict(description=u"Database ID of the Pokémon"))
1416 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
1417 info=dict(description=u"Database ID of the generation"))
1418 game_index = Column(Integer, nullable=False,
1419 info=dict(description=u"Internal ID the generation's games use for the Pokémon"))
1420
1421 class PokemonItem(TableBase):
1422 u"""Record of an item a Pokémon can hold in the wild
1423 """
1424 __tablename__ = 'pokemon_items'
1425 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1426 info=dict(description=u"ID of the Pokémon"))
1427 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
1428 info=dict(description=u"ID of the version this applies to"))
1429 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, nullable=False, autoincrement=False,
1430 info=dict(description=u"ID of the item"))
1431 rarity = Column(Integer, nullable=False,
1432 info=dict(description=u"Chance of the Pokémon holding the item, in percent"))
1433
1434 class PokemonMove(TableBase):
1435 u"""Record of a move a Pokémon can learn
1436 """
1437 __tablename__ = 'pokemon_moves'
1438 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, index=True,
1439 info=dict(description=u"ID of the Pokémon"))
1440 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, index=True,
1441 info=dict(description=u"ID of the version group this applies to"))
1442 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False, index=True,
1443 info=dict(description=u"ID of the move"))
1444 pokemon_move_method_id = Column(Integer, ForeignKey('pokemon_move_methods.id'), nullable=False, index=True,
1445 info=dict(description=u"ID of the method this move is learned by"))
1446 level = Column(Integer, nullable=True, index=True,
1447 info=dict(description=u"Level the move is learned at, if applicable"))
1448 order = Column(Integer, nullable=True,
1449 info=dict(description=u"A sort key to produce the correct ordering when all else is equal")) # XXX: This needs a better description
1450
1451 __table_args__ = (
1452 PrimaryKeyConstraint('pokemon_id', 'version_group_id', 'move_id', 'pokemon_move_method_id', 'level'),
1453 {},
1454 )
1455
1456 class PokemonMoveMethod(TableBase):
1457 u"""A method a move can be learned by, such as "Level up" or "Tutor".
1458 """
1459 __tablename__ = 'pokemon_move_methods'
1460 __singlename__ = 'pokemon_move_method'
1461 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1462 info=dict(description=u"A numeric ID"))
1463 identifier = Column(Unicode(64), nullable=False,
1464 info=dict(description=u"An identifier", format='identifier'))
1465
1466 create_translation_table('pokemon_move_method_prose', PokemonMoveMethod, 'prose',
1467 relation_lazy='joined',
1468 name = Column(Unicode(64), nullable=False, index=True,
1469 info=dict(description="The name", format='plaintext', official=False)),
1470 description = Column(Unicode(255), nullable=False,
1471 info=dict(description=u"A detailed description of how the method works", format='plaintext')),
1472 )
1473
1474
1475 class PokemonShape(TableBase):
1476 u"""The shape of a Pokémon's body, as used in generation IV Pokédexes.
1477 """
1478 __tablename__ = 'pokemon_shapes'
1479 __singlename__ = 'pokemon_shape'
1480 id = Column(Integer, primary_key=True, nullable=False,
1481 info=dict(description=u"A numeric ID"))
1482 identifier = Column(Unicode(24), nullable=False,
1483 info=dict(description=u"An identifier", format='identifier'))
1484
1485 create_translation_table('pokemon_shape_prose', PokemonShape, 'prose',
1486 relation_lazy='joined',
1487 name = Column(Unicode(24), nullable=False, index=True,
1488 info=dict(description="The name", format='plaintext', official=False)),
1489 awesome_name = Column(Unicode(16), nullable=False,
1490 info=dict(description=u"A splendiferous name of the body shape", format='plaintext')),
1491 )
1492
1493 class PokemonStat(TableBase):
1494 u"""A stat value of a Pokémon
1495 """
1496 __tablename__ = 'pokemon_stats'
1497 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1498 info=dict(description=u"ID of the Pokémon"))
1499 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False,
1500 info=dict(description=u"ID of the stat"))
1501 base_stat = Column(Integer, nullable=False,
1502 info=dict(description=u"The base stat"))
1503 effort = Column(Integer, nullable=False,
1504 info=dict(description=u"The effort increase in this stat gained when this Pokémon is defeated"))
1505
1506 class PokemonType(TableBase):
1507 u"""Maps a type to a Pokémon. Each Pokémon has 1 or 2 types.
1508 """
1509 __tablename__ = 'pokemon_types'
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 type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
1513 info=dict(description=u"ID of the type"))
1514 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1515 info=dict(description=u"The type's slot, 1 or 2, used to sort types if there are two of them"))
1516
1517 class Region(TableBase):
1518 u"""Major areas of the world: Kanto, Johto, etc.
1519 """
1520 __tablename__ = 'regions'
1521 __singlename__ = 'region'
1522 id = Column(Integer, primary_key=True, nullable=False,
1523 info=dict(description=u"A numeric ID"))
1524 identifier = Column(Unicode(16), nullable=False,
1525 info=dict(description=u"An identifier", format='identifier'))
1526
1527 create_translation_table('region_names', Region, 'names',
1528 relation_lazy='joined',
1529 name = Column(Unicode(16), nullable=False, index=True,
1530 info=dict(description="The name", format='plaintext', official=True)),
1531 )
1532
1533 class Stat(TableBase):
1534 u"""A Stat, such as Attack or Speed
1535 """
1536 __tablename__ = 'stats'
1537 __singlename__ = 'stat'
1538 id = Column(Integer, primary_key=True, nullable=False,
1539 info=dict(description=u"A numeric ID"))
1540 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True,
1541 info=dict(description=u"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
1542 identifier = Column(Unicode(16), nullable=False,
1543 info=dict(description=u"An identifier", format='identifier'))
1544 is_battle_only = Column(Boolean, nullable=False,
1545 info=dict(description=u"Whether this stat only exists within a battle"))
1546
1547 create_translation_table('stat_names', Stat, 'names',
1548 relation_lazy='joined',
1549 name = Column(Unicode(16), nullable=False, index=True,
1550 info=dict(description="The name", format='plaintext', official=True)),
1551 )
1552
1553 class StatHint(TableBase):
1554 u"""Flavor text for genes that appears in a Pokémon's summary. Sometimes
1555 called "characteristics".
1556 """
1557 __tablename__ = 'stat_hints'
1558 __singlename__ = 'stat_hint'
1559 id = Column(Integer, primary_key=True, nullable=False,
1560 info=dict(description=u"A numeric ID"))
1561 stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
1562 info=dict(description=u"ID of the highest stat"))
1563 gene_mod_5 = Column(Integer, nullable=False, index=True,
1564 info=dict(description=u"Value of the highest stat modulo 5"))
1565
1566 create_translation_table('stat_hint_names', StatHint, 'names',
1567 relation_lazy='joined',
1568 message = Column(Unicode(24), nullable=False, index=True,
1569 info=dict(description=u"The text displayed", official=True, format='plaintext')),
1570 )
1571
1572 class SuperContestCombo(TableBase):
1573 u"""Combo of two moves in a Super Contest.
1574 """
1575 __tablename__ = 'super_contest_combos'
1576 first_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
1577 info=dict(description=u"The ID of the first move in the combo."))
1578 second_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
1579 info=dict(description=u"The ID of the second and last move."))
1580
1581 class SuperContestEffect(TableBase):
1582 u"""An effect a move can have when used in the Super Contest
1583 """
1584 __tablename__ = 'super_contest_effects'
1585 __singlename__ = 'super_contest_effect'
1586 id = Column(Integer, primary_key=True, nullable=False,
1587 info=dict(description=u"This effect's unique ID."))
1588 appeal = Column(SmallInteger, nullable=False,
1589 info=dict(description=u"The number of hearts the user gains."))
1590
1591 create_translation_table('super_contest_effect_prose', SuperContestEffect, 'prose',
1592 flavor_text = Column(Unicode(64), nullable=False,
1593 info=dict(description=u"A description of the effect.", format='plaintext', official=True)),
1594 )
1595
1596
1597 class TypeEfficacy(TableBase):
1598 u"""The damage multiplier used when a move of a particular type damages a
1599 Pokémon of a particular other type.
1600 """
1601 __tablename__ = 'type_efficacy'
1602 damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1603 info=dict(description=u"The ID of the damaging type."))
1604 target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1605 info=dict(description=u"The ID of the defending Pokémon's type."))
1606 damage_factor = Column(Integer, nullable=False,
1607 info=dict(description=u"The multiplier, as a percentage of damage inflicted."))
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 VersionGroup(TableBase):
1629 u"""A group of versions, containing either two paired versions (such as Red
1630 and Blue) or a single game (such as Yellow.)
1631 """
1632 __tablename__ = 'version_groups'
1633 id = Column(Integer, primary_key=True, nullable=False,
1634 info=dict(description=u"This version group's unique ID."))
1635 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
1636 info=dict(description=u"The ID of the generation the games in this group belong to."))
1637 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), nullable=False,
1638 info=dict(description=u"The ID of the regional Pokédex used in this version group."))
1639
1640 class VersionGroupRegion(TableBase):
1641 u"""Maps a version group to a region that appears in it."""
1642 __tablename__ = 'version_group_regions'
1643 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
1644 info=dict(description=u"The ID of the version group."))
1645 region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
1646 info=dict(description=u"The ID of the region."))
1647
1648 class Version(TableBase):
1649 u"""An individual main-series Pokémon game."""
1650 __tablename__ = 'versions'
1651 __singlename__ = 'version'
1652 id = Column(Integer, primary_key=True, nullable=False,
1653 info=dict(description=u"A unique ID for this version."))
1654 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
1655 info=dict(description=u"The ID of the version group this game belongs to."))
1656 identifier = Column(Unicode(32), nullable=False,
1657 info=dict(description=u'And identifier', format='identifier'))
1658
1659 create_translation_table('version_names', Version, 'names',
1660 relation_lazy='joined',
1661 name = Column(Unicode(32), nullable=False, index=True,
1662 info=dict(description="The name", format='plaintext', official=True)),
1663 )
1664
1665
1666 ### Relations down here, to avoid ordering problems
1667 Ability.changelog = relation(AbilityChangelog,
1668 order_by=AbilityChangelog.changed_in_version_group_id.desc(),
1669 backref='ability',
1670 )
1671 Ability.flavor_text = relation(AbilityFlavorText, order_by=AbilityFlavorText.version_group_id, backref='ability')
1672 Ability.generation = relation(Generation, backref='abilities')
1673
1674 AbilityChangelog.changed_in = relation(VersionGroup, backref='ability_changelog')
1675
1676 AbilityFlavorText.version_group = relation(VersionGroup)
1677 AbilityFlavorText.language = relation(Language)
1678
1679 Berry.berry_firmness = relation(BerryFirmness, backref='berries')
1680 Berry.firmness = association_proxy('berry_firmness', 'name')
1681 Berry.flavors = relation(BerryFlavor, order_by=BerryFlavor.contest_type_id, backref='berry')
1682 Berry.natural_gift_type = relation(Type)
1683
1684 BerryFlavor.contest_type = relation(ContestType)
1685
1686 ContestCombo.first = relation(Move, primaryjoin=ContestCombo.first_move_id==Move.id,
1687 backref='contest_combo_first')
1688 ContestCombo.second = relation(Move, primaryjoin=ContestCombo.second_move_id==Move.id,
1689 backref='contest_combo_second')
1690
1691 Encounter.location_area = relation(LocationArea, backref='encounters')
1692 Encounter.pokemon = relation(Pokemon, backref='encounters')
1693 Encounter.version = relation(Version, backref='encounters')
1694 Encounter.slot = relation(EncounterSlot, backref='encounters')
1695
1696 EncounterConditionValue.condition = relation(EncounterCondition, backref='values')
1697
1698 Encounter.condition_value_map = relation(EncounterConditionValueMap, backref='encounter')
1699 Encounter.condition_values = association_proxy('condition_value_map', 'condition_value')
1700 EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
1701 backref='encounter_map')
1702
1703 EncounterSlot.terrain = relation(EncounterTerrain, backref='slots')
1704 EncounterSlot.version_group = relation(VersionGroup)
1705
1706 EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
1707 EvolutionChain.baby_trigger_item = relation(Item, backref='evolution_chains')
1708
1709 Experience.growth_rate = relation(GrowthRate, backref='experience_table')
1710
1711 Generation.canonical_pokedex = relation(Pokedex, backref='canonical_for_generation')
1712 Generation.versions = relation(Version, secondary=VersionGroup.__table__)
1713 Generation.main_region = relation(Region)
1714
1715 GrowthRate.max_experience_obj = relation(Experience, primaryjoin=and_(Experience.growth_rate_id == GrowthRate.id, Experience.level == 100), uselist=False)
1716 GrowthRate.max_experience = association_proxy('max_experience_obj', 'experience')
1717
1718 Item.berry = relation(Berry, uselist=False, backref='item')
1719 Item.flags = relation(ItemFlag, secondary=ItemFlagMap.__table__)
1720 Item.flavor_text = relation(ItemFlavorText, order_by=ItemFlavorText.version_group_id.asc(), backref='item')
1721 Item.fling_effect = relation(ItemFlingEffect, backref='items')
1722 Item.machines = relation(Machine, order_by=Machine.version_group_id.asc())
1723 Item.category = relation(ItemCategory)
1724 Item.pocket = association_proxy('category', 'pocket')
1725
1726 ItemCategory.items = relation(Item, order_by=Item.identifier)
1727 ItemCategory.pocket = relation(ItemPocket)
1728
1729 ItemFlavorText.version_group = relation(VersionGroup)
1730 ItemFlavorText.language = relation(Language)
1731
1732 ItemGameIndex.item = relation(Item, backref='game_indices')
1733 ItemGameIndex.generation = relation(Generation)
1734
1735 ItemPocket.categories = relation(ItemCategory, order_by=ItemCategory.identifier)
1736
1737 Location.region = relation(Region, backref='locations')
1738
1739 LocationArea.location = relation(Location, backref='areas')
1740
1741 LocationGameIndex.location = relation(Location, backref='game_indices')
1742 LocationGameIndex.generation = relation(Generation)
1743
1744 Machine.item = relation(Item)
1745 Machine.version_group = relation(VersionGroup)
1746
1747 Move.changelog = relation(MoveChangelog,
1748 order_by=MoveChangelog.changed_in_version_group_id.desc(),
1749 backref='move',
1750 )
1751 Move.contest_effect = relation(ContestEffect, backref='moves')
1752 Move.contest_combo_next = association_proxy('contest_combo_first', 'second')
1753 Move.contest_combo_prev = association_proxy('contest_combo_second', 'first')
1754 Move.contest_type = relation(ContestType, backref='moves')
1755 Move.damage_class = relation(MoveDamageClass, backref='moves')
1756 Move.flags = association_proxy('move_flags', 'flag')
1757 Move.flavor_text = relation(MoveFlavorText, order_by=MoveFlavorText.version_group_id, backref='move')
1758 Move.generation = relation(Generation, backref='moves')
1759 Move.machines = relation(Machine, backref='move')
1760 Move.meta = relation(MoveMeta, uselist=False, backref='move')
1761 Move.meta_stat_changes = relation(MoveMetaStatChange)
1762 Move.move_effect = relation(MoveEffect, backref='moves')
1763 Move.move_flags = relation(MoveFlag, backref='move')
1764 Move.super_contest_effect = relation(SuperContestEffect, backref='moves')
1765 Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
1766 Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
1767 Move.target = relation(MoveTarget, backref='moves')
1768 Move.type = relation(Type, backref='moves')
1769
1770 Move.effect = markdown.MoveEffectProperty('effect')
1771 Move.effect_map = markdown.MoveEffectProperty('effect_map')
1772 Move.short_effect = markdown.MoveEffectProperty('short_effect')
1773 Move.short_effect_map = markdown.MoveEffectProperty('short_effect_map')
1774
1775 MoveChangelog.changed_in = relation(VersionGroup, backref='move_changelog')
1776 MoveChangelog.move_effect = relation(MoveEffect, backref='move_changelog')
1777 MoveChangelog.type = relation(Type, backref='move_changelog')
1778
1779 MoveChangelog.effect = markdown.MoveEffectProperty('effect')
1780 MoveChangelog.effect_map = markdown.MoveEffectProperty('effect_map')
1781 MoveChangelog.short_effect = markdown.MoveEffectProperty('short_effect')
1782 MoveChangelog.short_effect_map = markdown.MoveEffectProperty('short_effect_map')
1783
1784 MoveEffect.category_map = relation(MoveEffectCategoryMap)
1785 MoveEffect.categories = association_proxy('category_map', 'category')
1786 MoveEffect.changelog = relation(MoveEffectChangelog,
1787 order_by=MoveEffectChangelog.changed_in_version_group_id.desc(),
1788 backref='move_effect',
1789 )
1790 MoveEffectCategoryMap.category = relation(MoveEffectCategory)
1791
1792 MoveEffectChangelog.changed_in = relation(VersionGroup, backref='move_effect_changelog')
1793
1794 MoveFlag.flag = relation(MoveFlagType)
1795
1796 MoveFlavorText.version_group = relation(VersionGroup)
1797 MoveFlavorText.language = relation(Language)
1798
1799 MoveMeta.category = relation(MoveMetaCategory, backref='move_meta')
1800 MoveMeta.ailment = relation(MoveMetaAilment, backref='move_meta')
1801
1802 MoveMetaStatChange.stat = relation(Stat, backref='move_meta_stat_changes')
1803
1804 Nature.decreased_stat = relation(Stat, primaryjoin=Nature.decreased_stat_id==Stat.id,
1805 backref='decreasing_natures')
1806 Nature.increased_stat = relation(Stat, primaryjoin=Nature.increased_stat_id==Stat.id,
1807 backref='increasing_natures')
1808 Nature.hates_flavor = relation(ContestType, primaryjoin=Nature.hates_flavor_id==ContestType.id,
1809 backref='hating_natures')
1810 Nature.likes_flavor = relation(ContestType, primaryjoin=Nature.likes_flavor_id==ContestType.id,
1811 backref='liking_natures')
1812 Nature.battle_style_preferences = relation(NatureBattleStylePreference,
1813 order_by=NatureBattleStylePreference.move_battle_style_id,
1814 backref='nature')
1815 Nature.pokeathlon_effects = relation(NaturePokeathlonStat, order_by=NaturePokeathlonStat.pokeathlon_stat_id)
1816
1817 NatureBattleStylePreference.battle_style = relation(MoveBattleStyle, backref='nature_preferences')
1818
1819 NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat, backref='nature_effects')
1820
1821 Pokedex.region = relation(Region, backref='pokedexes')
1822 Pokedex.version_groups = relation(VersionGroup, order_by=VersionGroup.id, backref='pokedex')
1823
1824 Pokemon.all_abilities = relation(Ability,
1825 secondary=PokemonAbility.__table__,
1826 order_by=PokemonAbility.slot,
1827 backref=backref('all_pokemon',
1828 order_by=Pokemon.order,
1829 ),
1830 )
1831 Pokemon.abilities = relation(Ability,
1832 secondary=PokemonAbility.__table__,
1833 primaryjoin=and_(
1834 Pokemon.id == PokemonAbility.pokemon_id,
1835 PokemonAbility.is_dream == False,
1836 ),
1837 order_by=PokemonAbility.slot,
1838 backref=backref('pokemon',
1839 order_by=Pokemon.order,
1840 ),
1841 )
1842 Pokemon.dream_ability = relation(Ability,
1843 secondary=PokemonAbility.__table__,
1844 primaryjoin=and_(
1845 Pokemon.id == PokemonAbility.pokemon_id,
1846 PokemonAbility.is_dream == True,
1847 ),
1848 uselist=False,
1849 backref=backref('dream_pokemon',
1850 order_by=Pokemon.order,
1851 ),
1852 )
1853 Pokemon.pokemon_color = relation(PokemonColor, backref='pokemon')
1854 Pokemon.color = association_proxy('pokemon_color', 'name')
1855 Pokemon.dex_numbers = relation(PokemonDexNumber, order_by=PokemonDexNumber.pokedex_id.asc(), backref='pokemon')
1856 Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
1857 order_by=PokemonEggGroup.egg_group_id,
1858 backref=backref('pokemon', order_by=Pokemon.order))
1859 Pokemon.evolution_chain = relation(EvolutionChain, backref=backref('pokemon', order_by=Pokemon.order))
1860 Pokemon.child_pokemon = relation(Pokemon,
1861 primaryjoin=Pokemon.id==PokemonEvolution.from_pokemon_id,
1862 secondary=PokemonEvolution.__table__,
1863 secondaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
1864 backref=backref('parent_pokemon', uselist=False),
1865 )
1866 Pokemon.flavor_text = relation(PokemonFlavorText, order_by=PokemonFlavorText.version_id.asc(), backref='pokemon')
1867 Pokemon.forms = relation(PokemonForm, primaryjoin=Pokemon.id==PokemonForm.form_base_pokemon_id,
1868 order_by=(PokemonForm.order.asc(), PokemonForm.identifier.asc()))
1869 Pokemon.default_form = relation(PokemonForm,
1870 primaryjoin=and_(Pokemon.id==PokemonForm.form_base_pokemon_id, PokemonForm.is_default==True),
1871 uselist=False,
1872 )
1873 Pokemon.pokemon_habitat = relation(PokemonHabitat, backref='pokemon')
1874 Pokemon.habitat = association_proxy('pokemon_habitat', 'name')
1875 Pokemon.items = relation(PokemonItem, backref='pokemon')
1876 Pokemon.generation = relation(Generation, backref='pokemon')
1877 Pokemon.shape = relation(PokemonShape, backref='pokemon')
1878 Pokemon.stats = relation(PokemonStat, backref='pokemon', order_by=PokemonStat.stat_id.asc())
1879 Pokemon.types = relation(Type,
1880 secondary=PokemonType.__table__,
1881 order_by=PokemonType.slot.asc(),
1882 backref=backref('pokemon', order_by=Pokemon.order),
1883 )
1884
1885 PokemonDexNumber.pokedex = relation(Pokedex)
1886
1887 PokemonEvolution.from_pokemon = relation(Pokemon,
1888 primaryjoin=PokemonEvolution.from_pokemon_id==Pokemon.id,
1889 backref='child_evolutions',
1890 )
1891 PokemonEvolution.to_pokemon = relation(Pokemon,
1892 primaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
1893 backref=backref('parent_evolution', uselist=False),
1894 )
1895 PokemonEvolution.child_evolutions = relation(PokemonEvolution,
1896 primaryjoin=PokemonEvolution.from_pokemon_id==PokemonEvolution.to_pokemon_id,
1897 foreign_keys=[PokemonEvolution.to_pokemon_id],
1898 backref=backref('parent_evolution',
1899 remote_side=[PokemonEvolution.from_pokemon_id],
1900 uselist=False,
1901 ),
1902 )
1903 PokemonEvolution.trigger = relation(EvolutionTrigger, backref='evolutions')
1904 PokemonEvolution.trigger_item = relation(Item,
1905 primaryjoin=PokemonEvolution.trigger_item_id==Item.id,
1906 backref='triggered_evolutions',
1907 )
1908 PokemonEvolution.held_item = relation(Item,
1909 primaryjoin=PokemonEvolution.held_item_id==Item.id,
1910 backref='required_for_evolutions',
1911 )
1912 PokemonEvolution.location = relation(Location, backref='triggered_evolutions')
1913 PokemonEvolution.known_move = relation(Move, backref='triggered_evolutions')
1914 PokemonEvolution.party_pokemon = relation(Pokemon,
1915 primaryjoin=PokemonEvolution.party_pokemon_id==Pokemon.id,
1916 backref='triggered_evolutions',
1917 )
1918 PokemonEvolution.trade_pokemon = relation(Pokemon,
1919 primaryjoin=PokemonEvolution.trade_pokemon_id==Pokemon.id,
1920 )
1921
1922 PokemonFlavorText.version = relation(Version)
1923 PokemonFlavorText.language = relation(Language)
1924
1925 PokemonForm.form_base_pokemon = relation(Pokemon, primaryjoin=PokemonForm.form_base_pokemon_id==Pokemon.id)
1926 PokemonForm.unique_pokemon = relation(Pokemon, backref=backref('unique_form', uselist=False),
1927 primaryjoin=PokemonForm.unique_pokemon_id==Pokemon.id)
1928 PokemonForm.version_group = relation(VersionGroup)
1929 PokemonForm.form_group = association_proxy('form_base_pokemon', 'form_group')
1930 PokemonForm.pokeathlon_stats = relation(PokemonFormPokeathlonStat,
1931 order_by=PokemonFormPokeathlonStat.pokeathlon_stat_id,
1932 backref='pokemon_form')
1933
1934 PokemonFormGroup.pokemon = relation(Pokemon, backref=backref('form_group',
1935 uselist=False))
1936
1937 PokemonFormPokeathlonStat.pokeathlon_stat = relation(PokeathlonStat)
1938
1939 PokemonItem.item = relation(Item, backref='pokemon')
1940 PokemonItem.version = relation(Version)
1941
1942 PokemonMove.pokemon = relation(Pokemon, backref='pokemon_moves')
1943 PokemonMove.version_group = relation(VersionGroup)
1944 PokemonMove.machine = relation(Machine, backref='pokemon_moves',
1945 primaryjoin=and_(Machine.version_group_id==PokemonMove.version_group_id,
1946 Machine.move_id==PokemonMove.move_id),
1947 foreign_keys=[Machine.version_group_id, Machine.move_id],
1948 uselist=False)
1949 PokemonMove.move = relation(Move, backref='pokemon_moves')
1950 PokemonMove.method = relation(PokemonMoveMethod)
1951
1952 PokemonStat.stat = relation(Stat)
1953
1954 # This is technically a has-many; Generation.main_region_id -> Region.id
1955 Region.generation = relation(Generation, uselist=False)
1956 Region.version_group_regions = relation(VersionGroupRegion, backref='region',
1957 order_by='VersionGroupRegion.version_group_id')
1958 Region.version_groups = association_proxy('version_group_regions', 'version_group')
1959
1960 Stat.damage_class = relation(MoveDamageClass, backref='stats')
1961
1962 StatHint.stat = relation(Stat, backref='hints')
1963
1964 SuperContestCombo.first = relation(Move, primaryjoin=SuperContestCombo.first_move_id==Move.id,
1965 backref='super_contest_combo_first')
1966 SuperContestCombo.second = relation(Move, primaryjoin=SuperContestCombo.second_move_id==Move.id,
1967 backref='super_contest_combo_second')
1968
1969 Type.damage_efficacies = relation(TypeEfficacy,
1970 primaryjoin=Type.id
1971 ==TypeEfficacy.damage_type_id,
1972 backref='damage_type')
1973 Type.target_efficacies = relation(TypeEfficacy,
1974 primaryjoin=Type.id
1975 ==TypeEfficacy.target_type_id,
1976 backref='target_type')
1977
1978 Type.generation = relation(Generation, backref='types')
1979 Type.damage_class = relation(MoveDamageClass, backref='types')
1980
1981 Version.generation = association_proxy('version_group', 'generation')
1982
1983 VersionGroup.versions = relation(Version, order_by=Version.id, backref='version_group')
1984 VersionGroup.generation = relation(Generation, backref='version_groups')
1985 VersionGroup.version_group_regions = relation(VersionGroupRegion, backref='version_group')
1986 VersionGroup.regions = association_proxy('version_group_regions', 'region')