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