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