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