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