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