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