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