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