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