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