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