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