Version group Pokédexes don't need their own table.
[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 MoveChangelog(TableBase):
676 """History of changes to moves across main game versions."""
677 __tablename__ = 'move_changelog'
678 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
679 info=dict(description="ID of the move that changed"))
680 changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
681 info=dict(description="ID of the version group in which the move changed"))
682 power = Column(SmallInteger, nullable=True,
683 info=dict(description="Prior base power of the move, or NULL if unchanged"))
684 pp = Column(SmallInteger, nullable=True,
685 info=dict(description="Prior base PP of the move, or NULL if unchanged"))
686 accuracy = Column(SmallInteger, nullable=True,
687 info=dict(description="Prior accuracy of the move, or NULL if unchanged"))
688
689 class Nature(TableBase):
690 u"""A nature a pokémon can have, such as Calm or Brave
691 """
692 __tablename__ = 'natures'
693 __singlename__ = 'nature'
694 id = Column(Integer, primary_key=True, nullable=False,
695 info=dict(description="A numeric ID"))
696 name = Column(Unicode(8), nullable=False,
697 info=dict(description="An English name of the nature", official=True, format='plaintext'))
698 decreased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
699 info=dict(description="ID of the stat that this nature decreases by 10% (if decreased_stat_id is the same, the effects cancel out)"))
700 increased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
701 info=dict(description="ID of the stat that this nature increases by 10% (if decreased_stat_id is the same, the effects cancel out)"))
702 hates_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False,
703 info=dict(description=u"ID of the Berry flavor the Pokémon hates (if likes_flavor_id is the same, the effects cancel out)"))
704 likes_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False,
705 info=dict(description=u"ID of the Berry flavor the Pokémon likes (if hates_flavor_id is the same, the effects cancel out)"))
706
707 @property
708 def is_neutral(self):
709 u"""Returns True iff this nature doesn't alter a Pokémon's stats,
710 bestow taste preferences, etc.
711 """
712 return self.increased_stat_id == self.decreased_stat_id
713
714 class NatureBattleStylePreference(TableBase):
715 u"""Battle Palace move preference
716
717 Specifies how likely a pokémon with a specific Nature is to use a move of
718 a particular battl style in Battle Palace or Battle Tent
719 """
720 __tablename__ = 'nature_battle_style_preferences'
721 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
722 info=dict(description=u"ID of the pokémon's nature"))
723 move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False,
724 info=dict(description="ID of the battle style"))
725 low_hp_preference = Column(Integer, nullable=False,
726 info=dict(description=u"Chance of using the move, in percent, if HP is under ½"))
727 high_hp_preference = Column(Integer, nullable=False,
728 info=dict(description=u"Chance of using the move, in percent, if HP is over ½"))
729
730 class NatureName(TableBase):
731 u"""Non-english name of a Nature
732 """
733 __tablename__ = 'nature_names'
734 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False, autoincrement=False,
735 info=dict(description="ID of the nature"))
736 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
737 info=dict(description="ID of the language"))
738 name = Column(Unicode(8), nullable=False,
739 info=dict(description="The nature's foreign name", foreign=True, format='plaintext'))
740
741 class NaturePokeathlonStat(TableBase):
742 u"""Specifies how a Nature affects a Pokéathlon stat
743 """
744 __tablename__ = 'nature_pokeathlon_stats'
745 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
746 info=dict(description="ID of the nature"))
747 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False,
748 info=dict(description="ID of the stat"))
749 max_change = Column(Integer, nullable=False,
750 info=dict(description="Maximum change"))
751
752 class PokeathlonStat(TableBase):
753 u"""A Pokéathlon stat, such as "Stamina" or "Jump".
754 """
755 __tablename__ = 'pokeathlon_stats'
756 id = Column(Integer, primary_key=True, nullable=False,
757 info=dict(description="A numeric ID"))
758 name = Column(Unicode(8), nullable=False,
759 info=dict(description="The English name of the stat", official=True, format='plaintext'))
760
761 class Pokedex(TableBase):
762 u"""A collection of pokémon species ordered in a particular way
763 """
764 __tablename__ = 'pokedexes'
765 id = Column(Integer, primary_key=True, nullable=False,
766 info=dict(description="A numeric ID"))
767 region_id = Column(Integer, ForeignKey('regions.id'), nullable=True,
768 info=dict(description=u"ID of the region this pokédex is used in, or None if it's global"))
769 name = Column(Unicode(16), nullable=False,
770 info=dict(description=u"An English name of the pokédex", format='plaintext'))
771 description = Column(Unicode(512),
772 info=dict(description=u"A longer description of the pokédex", format='plaintext'))
773
774 class Pokemon(TableBase):
775 u"""A species of Pokémon. The core to this whole mess.
776 """
777 __tablename__ = 'pokemon'
778 __singlename__ = 'pokemon'
779 id = Column(Integer, primary_key=True, nullable=False,
780 info=dict(description=u"A numeric ID"))
781 name = Column(Unicode(20), nullable=False,
782 info=dict(description=u"The English name of the Pokémon", official=True, format='plaintext'))
783 generation_id = Column(Integer, ForeignKey('generations.id'),
784 info=dict(description=u"ID of the generation this species first appeared in"))
785 evolution_chain_id = Column(Integer, ForeignKey('evolution_chains.id'),
786 info=dict(description=u"ID of the species' evolution chain (a.k.a. family)"))
787 height = Column(Integer, nullable=False,
788 info=dict(description=u"The height of the pokémon, in decimeters (tenths of a meter)"))
789 weight = Column(Integer, nullable=False,
790 info=dict(description=u"The weight of the pokémon, in tenths of a kilogram (decigrams)"))
791 species = Column(Unicode(16), nullable=False,
792 info=dict(description=u'The short English flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
793 official=True, format='plaintext'))
794 color_id = Column(Integer, ForeignKey('pokemon_colors.id'), nullable=False,
795 info=dict(description=u"ID of this pokémon's pokédex color, as used for a gimmick search function in the games."))
796 pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=True,
797 info=dict(description=u"ID of this pokémon's body shape, as used for a gimmick search function in the games."))
798 habitat_id = Column(Integer, ForeignKey('pokemon_habitats.id'), nullable=True,
799 info=dict(description=u"ID of this pokémon's habitat, as used for a gimmick search function in the games."))
800 gender_rate = Column(Integer, nullable=False,
801 info=dict(description=u"The chance of this pokémon being female, in eighths; or -1 for genderless"))
802 capture_rate = Column(Integer, nullable=False,
803 info=dict(description=u"The base capture rate; up to 255"))
804 base_experience = Column(Integer, nullable=False,
805 info=dict(description=u"The base EXP gained when defeating this pokémon")) # XXX: Is this correct?
806 base_happiness = Column(Integer, nullable=False,
807 info=dict(description=u"The tameness when caught by a normal ball"))
808 is_baby = Column(Boolean, nullable=False,
809 info=dict(description=u"True iff the pokémon is a baby")) # XXX: What exactly makes it a baby?
810 hatch_counter = Column(Integer, nullable=False,
811 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"))
812 has_gen4_fem_sprite = Column(Boolean, nullable=False,
813 info=dict(description=u"Set iff the species' female front sprite is different from the male's in generation IV"))
814 has_gen4_fem_back_sprite = Column(Boolean, nullable=False,
815 info=dict(description=u"Set iff the species' female back sprite is different from the male's in generation IV"))
816
817 ### Stuff to handle alternate Pokémon forms
818
819 @property
820 def is_base_form(self):
821 u"""Returns True iff the Pokémon is the base form for its species,
822 e.g. Land Shaymin.
823 """
824
825 return self.unique_form is None or self.unique_form.is_default
826
827 @property
828 def form_name(self):
829 u"""Returns the Pokémon's form name if it represents a particular form
830 and that form has a name, or None otherwise.
831 """
832
833 # If self.unique_form is None, the short-circuit "and" will go ahead
834 # and return that. Otherwise, it'll return the form's name, which may
835 # also be None.
836 return self.unique_form and self.unique_form.name
837
838 @property
839 def full_name(self):
840 u"""Returns the Pokémon's name, including its form if applicable."""
841
842 if self.form_name:
843 return '{0} {1}'.format(self.form_name, self.name)
844 else:
845 return self.name
846
847 @property
848 def normal_form(self):
849 u"""Returns the normal form for this Pokémon; i.e., this will return
850 regular Deoxys when called on any Deoxys form.
851 """
852
853 if self.unique_form:
854 return self.unique_form.form_base_pokemon
855 return self
856
857 ### Not forms!
858
859 def stat(self, stat_name):
860 u"""Returns a PokemonStat record for the given stat name (or Stat row
861 object). Uses the normal has-many machinery, so all the stats are
862 effectively cached.
863 """
864 if isinstance(stat_name, Stat):
865 stat_name = stat_name.name
866
867 for pokemon_stat in self.stats:
868 if pokemon_stat.stat.name == stat_name:
869 return pokemon_stat
870
871 raise KeyError(u'No stat named %s' % stat_name)
872
873 @property
874 def better_damage_class(self):
875 u"""Returns the MoveDamageClass that this Pokémon is best suited for,
876 based on its attack stats.
877
878 If the attack stats are about equal (within 5), returns None. The
879 value None, not the damage class called 'None'.
880 """
881 phys = self.stat(u'Attack')
882 spec = self.stat(u'Special Attack')
883
884 diff = phys.base_stat - spec.base_stat
885
886 if diff > 5:
887 return phys.stat.damage_class
888 elif diff < -5:
889 return spec.stat.damage_class
890 else:
891 return None
892
893 class PokemonAbility(TableBase):
894 u"""Maps an ability to a pokémon that can have it
895 """
896 __tablename__ = 'pokemon_abilities'
897 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
898 info=dict(description=u"ID of the pokémon"))
899 ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
900 info=dict(description=u"ID of the ability"))
901 # XXX having both a method and a slot is kind of gross. "slot" is a
902 # misnomer, anyway: duplicate abilities don't appear in slot 2.
903 # Probably should replace that with "order".
904 is_dream = Column(Boolean, nullable=False, index=True,
905 info=dict(description=u"Whether this is a Dream World ability"))
906 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
907 info=dict(description=u"The ability slot, i.e. 1 or 2 for gen. IV"))
908
909 class PokemonColor(TableBase):
910 u"""The "pokédex color" of a pokémon species. Usually based on the pokémon's color.
911 """
912 __tablename__ = 'pokemon_colors'
913 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
914 info=dict(description=u"ID of the pokémon"))
915 name = Column(Unicode(6), nullable=False,
916 info=dict(description=u"The English name of the color", official=True, format='identifier'))
917
918 class PokemonDexNumber(TableBase):
919 u"""The number of a Pokémon in a particular Pokédex (e.g. Jigglypuff is #138 in Hoenn's 'dex)
920 """
921 __tablename__ = 'pokemon_dex_numbers'
922 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
923 info=dict(description=u"ID of the pokémon"))
924 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), primary_key=True, nullable=False, autoincrement=False,
925 info=dict(description=u"ID of the pokédex"))
926 pokedex_number = Column(Integer, nullable=False,
927 info=dict(description=u"Number of the pokémon in that the pokédex"))
928
929 class PokemonEggGroup(TableBase):
930 u"""Maps an Egg group to a pokémon; each pokémon belongs to one or two egg groups
931 """
932 __tablename__ = 'pokemon_egg_groups'
933 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
934 info=dict(description=u"ID of the pokémon"))
935 egg_group_id = Column(Integer, ForeignKey('egg_groups.id'), primary_key=True, nullable=False, autoincrement=False,
936 info=dict(description=u"ID of the egg group"))
937
938 class PokemonEvolution(TableBase):
939 u"""Specifies what causes a particular pokémon to evolve into another species.
940 """
941 __tablename__ = 'pokemon_evolution'
942 from_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False,
943 info=dict(description=u"ID of the pre-evolution species"))
944 to_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
945 info=dict(description=u"ID of the post-evolution species"))
946 evolution_trigger_id = Column(Integer, ForeignKey('evolution_triggers.id'), nullable=False,
947 info=dict(description=u"ID of the trigger type"))
948 trigger_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
949 info=dict(description=u"ID of the item that triggers the evolution in a way defined by evolution_trigger_id"))
950 minimum_level = Column(Integer, nullable=True,
951 info=dict(description=u"Minimum level, or None if level doean't matter"))
952 gender = Column(Enum('male', 'female', name='pokemon_evolution_gender'), nullable=True,
953 info=dict(description=u"Required gender, or None if gender doesn't matter"))
954 location_id = Column(Integer, ForeignKey('locations.id'), nullable=True,
955 info=dict(description=u"Required location, or None if it doesn't matter"))
956 held_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
957 info=dict(description=u"An item the pokémon must hold, or None if it doesn't matter"))
958 time_of_day = Column(Enum('morning', 'day', 'night', name='pokemon_evolution_time_of_day'), nullable=True,
959 info=dict(description=u"Required time of day, or None if it doesn't matter"))
960 known_move_id = Column(Integer, ForeignKey('moves.id'), nullable=True,
961 info=dict(description=u"ID of a move the pokémon must know, or None if it doesn't matter"))
962 minimum_happiness = Column(Integer, nullable=True,
963 info=dict(description=u"Minimum tameness value the pokémon must have, or None if it doesn't matter"))
964 minimum_beauty = Column(Integer, nullable=True,
965 info=dict(description=u"Minimum Beauty value the pokémon must have, or None if it doesn't matter"))
966 relative_physical_stats = Column(Integer, nullable=True,
967 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"))
968 party_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True,
969 info=dict(description=u"ID of a pokémon that must be present in the party, or None if there's no such condition"))
970
971 class PokemonFlavorText(TableBase):
972 u"""In-game pokédex descrption of a pokémon.
973 """
974 __tablename__ = 'pokemon_flavor_text'
975 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
976 info=dict(description=u"ID of the pokémon"))
977 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
978 info=dict(description=u"ID of the version that has this flavor text"))
979 flavor_text = Column(Unicode(255), nullable=False,
980 info=dict(description=u"ID of the version that has this flavor text", official=True, format='gametext'))
981
982 class PokemonForm(TableBase):
983 u"""An individual form of a Pokémon.
984
985 Pokémon that do not have separate forms are still given a single row to
986 represent their single form.
987 """
988 __tablename__ = 'pokemon_forms'
989 __singlename__ = 'pokemon_form'
990 id = Column(Integer, primary_key=True, nullable=False,
991 info=dict(description=u'A unique ID for this form.'))
992 name = Column(Unicode(16), nullable=True,
993 info=dict(description=u"This form's name, e.g. \"Plant\" for Plant Cloak Burmy.", official=True, format='plaintext'))
994 form_base_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
995 info=dict(description=u'The ID of the base Pokémon for this form.'))
996 unique_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), autoincrement=False,
997 info=dict(description=u'The ID of a Pokémon that represents specifically this form, for Pokémon with functionally-different forms like Wormadam.'))
998 introduced_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), autoincrement=False,
999 info=dict(description=u'The ID of the version group in which this form first appeared.'))
1000 is_default = Column(Boolean, nullable=False,
1001 info=dict(description=u'Set for exactly one form used as the default for each species.'))
1002 order = Column(Integer, nullable=False, autoincrement=False,
1003 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.'))
1004
1005 @property
1006 def full_name(self):
1007 u"""Returns the full name of this form, e.g. "Plant Cloak"."""
1008
1009 if not self.name:
1010 return None
1011 elif self.form_group and self.form_group.term:
1012 return '{0} {1}'.format(self.name, self.form_group.term)
1013 else:
1014 return self.name
1015
1016 @property
1017 def pokemon_name(self):
1018 u"""Returns the name of this Pokémon with this form, e.g. "Plant
1019 Burmy".
1020 """
1021
1022 if self.name:
1023 return '{0} {1}'.format(self.name, self.form_base_pokemon.name)
1024 else:
1025 return self.form_base_pokemon.name
1026
1027 class PokemonFormGroup(TableBase):
1028 u"""Information about a Pokémon's forms as a group."""
1029 __tablename__ = 'pokemon_form_groups'
1030 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1031 info=dict(description=u"ID of the base form Pokémon"))
1032 term = Column(Unicode(16), nullable=True,
1033 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'))
1034 is_battle_only = Column(Boolean, nullable=False,
1035 info=dict(description=u"Set iff the forms only change in battle"))
1036 description = Column(markdown.MarkdownColumn(1024), nullable=False,
1037 info=dict(description=u"English description of how the forms work", format='markdown'))
1038
1039 class PokemonFormPokeathlonStat(TableBase):
1040 u"""A Pokémon form's performance in one Pokéathlon stat."""
1041 __tablename__ = 'pokemon_form_pokeathlon_stats'
1042 pokemon_form_id = Column(Integer, ForeignKey('pokemon_forms.id'), primary_key=True, nullable=False, autoincrement=False,
1043 info=dict(description=u'The ID of the Pokémon form.'))
1044 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False, autoincrement=False,
1045 info=dict(description=u'The ID of the Pokéathlon stat.'))
1046 minimum_stat = Column(Integer, nullable=False, autoincrement=False,
1047 info=dict(description=u'The minimum value for this stat for this Pokémon form.'))
1048 base_stat = Column(Integer, nullable=False, autoincrement=False,
1049 info=dict(description=u'The default value for this stat for this Pokémon form.'))
1050 maximum_stat = Column(Integer, nullable=False, autoincrement=False,
1051 info=dict(description=u'The maximum value for this stat for this Pokémon form.'))
1052
1053 class PokemonHabitat(TableBase):
1054 u"""The habitat of a pokémon, as given in the FireRed/LeafGreen version pokédex
1055 """
1056 __tablename__ = 'pokemon_habitats'
1057 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1058 info=dict(description=u"A numeric ID"))
1059 name = Column(Unicode(16), nullable=False,
1060 info=dict(description=u"The English name of the habitat", official=True, format='plaintext'))
1061
1062 class PokemonInternalID(TableBase):
1063 u"""The number of a pokémon a game uses internally
1064 """
1065 __tablename__ = 'pokemon_internal_ids'
1066 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False,
1067 info=dict(description=u"Database ID of the pokémon"))
1068 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
1069 info=dict(description=u"Database ID of the generation"))
1070 internal_id = Column(Integer, nullable=False,
1071 info=dict(description=u"Internal ID the generation's games use for the pokémon"))
1072
1073 class PokemonItem(TableBase):
1074 u"""Record of an item a pokémon can hold in the wild
1075 """
1076 __tablename__ = 'pokemon_items'
1077 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1078 info=dict(description=u"ID of the pokémon"))
1079 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
1080 info=dict(description=u"ID of the version this applies to"))
1081 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, nullable=False, autoincrement=False,
1082 info=dict(description=u"ID of the item"))
1083 rarity = Column(Integer, nullable=False,
1084 info=dict(description=u"Chance of the pokémon holding the item, in percent"))
1085
1086 class PokemonMove(TableBase):
1087 u"""Record of a move a pokémon can learn
1088 """
1089 __tablename__ = 'pokemon_moves'
1090 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, index=True,
1091 info=dict(description=u"ID of the pokémon"))
1092 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, index=True,
1093 info=dict(description=u"ID of the version group this applies to"))
1094 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False, index=True,
1095 info=dict(description=u"ID of the move"))
1096 pokemon_move_method_id = Column(Integer, ForeignKey('pokemon_move_methods.id'), nullable=False, index=True,
1097 info=dict(description=u"ID of the method this move is learned by"))
1098 level = Column(Integer, nullable=True, index=True,
1099 info=dict(description=u"Level the move is learned at, if applicable"))
1100 order = Column(Integer, nullable=True,
1101 info=dict(description=u"A sort key to produce the correct ordering when all else is equal")) # XXX: This needs a better description
1102
1103 __table_args__ = (
1104 PrimaryKeyConstraint('pokemon_id', 'version_group_id', 'move_id', 'pokemon_move_method_id', 'level'),
1105 {},
1106 )
1107
1108 class PokemonMoveMethod(TableBase):
1109 u"""A method a move can be learned by, such as "Level up" or "Tutor".
1110 """
1111 __tablename__ = 'pokemon_move_methods'
1112 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1113 info=dict(description=u"A numeric ID"))
1114 name = Column(Unicode(64), nullable=False,
1115 info=dict(description=u"An English name of the method", format='plaintext'))
1116 description = Column(Unicode(255), nullable=False,
1117 info=dict(description=u"A detailed description of how the method works", format='plaintext'))
1118
1119 class PokemonName(TableBase):
1120 u"""A non-English name of a pokémon.
1121 """
1122 __tablename__ = 'pokemon_names'
1123 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1124 info=dict(description=u"ID of the pokémon"))
1125 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
1126 info=dict(description=u"ID of the language"))
1127 name = Column(Unicode(16), nullable=False,
1128 info=dict(description=u"Name of the pokémon in the language", foreign=True, format='plaintext'))
1129
1130 class PokemonShape(TableBase):
1131 u"""The shape of a pokémon's body, as used in generation IV pokédexes.
1132 """
1133 __tablename__ = 'pokemon_shapes'
1134 id = Column(Integer, primary_key=True, nullable=False,
1135 info=dict(description=u"A numeric ID"))
1136 name = Column(Unicode(24), nullable=False,
1137 info=dict(description=u"A boring English name of the body shape", format='plaintext'))
1138 awesome_name = Column(Unicode(16), nullable=False,
1139 info=dict(description=u"A splendiferous, technically English, name of the body shape", format='plaintext'))
1140
1141 class PokemonStat(TableBase):
1142 u"""A stat value of a pokémon
1143 """
1144 __tablename__ = 'pokemon_stats'
1145 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1146 info=dict(description=u"ID of the pokémon"))
1147 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False,
1148 info=dict(description=u"ID of the stat"))
1149 base_stat = Column(Integer, nullable=False,
1150 info=dict(description=u"The base stat"))
1151 effort = Column(Integer, nullable=False,
1152 info=dict(description=u"The effort increase in this stat gained when this pokémon is defeated"))
1153
1154 class PokemonType(TableBase):
1155 u"""Maps a type to a pokémon. Each pokémon has 1 or 2 types.
1156 """
1157 __tablename__ = 'pokemon_types'
1158 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1159 info=dict(description=u"ID of the pokémon"))
1160 type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
1161 info=dict(description=u"ID of the type"))
1162 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1163 info=dict(description=u"The type's slot, 1 or 2, used to sort types if there are two of them"))
1164
1165 class Region(TableBase):
1166 u"""Major areas of the world: Kanto, Johto, etc.
1167 """
1168 __tablename__ = 'regions'
1169 id = Column(Integer, primary_key=True, nullable=False,
1170 info=dict(description=u"A numeric ID"))
1171 name = Column(Unicode(16), nullable=False,
1172 info=dict(description=u"The English name of the region", official=True, format='plaintext'))
1173
1174 class Stat(TableBase):
1175 u"""A Stat, such as Attack or Speed
1176 """
1177 __tablename__ = 'stats'
1178 id = Column(Integer, primary_key=True, nullable=False,
1179 info=dict(description=u"A numeric ID"))
1180 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True,
1181 info=dict(description=u"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
1182 name = Column(Unicode(16), nullable=False,
1183 info=dict(description=u"The English name of the stat", official=True, format='plaintext'))
1184
1185 class SuperContestCombo(TableBase):
1186 u"""Combo of two moves in a Super Contest.
1187 """
1188 __tablename__ = 'super_contest_combos'
1189 first_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
1190 info=dict(description=u"ID of the first move"))
1191 second_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
1192 info=dict(description=u"ID of the second and last move"))
1193
1194 class SuperContestEffect(TableBase):
1195 u"""An effect a move can have when used in the Super Contest
1196 """
1197 __tablename__ = 'super_contest_effects'
1198 id = Column(Integer, primary_key=True, nullable=False,
1199 info=dict(description=u"A numeric ID"))
1200 appeal = Column(SmallInteger, nullable=False,
1201 info=dict(description=u"Number of hearts the user will get when executing a move with this effect"))
1202 flavor_text = Column(Unicode(64), nullable=False,
1203 info=dict(description=u"An English description of the effect", format='plaintext'))
1204
1205 class TypeEfficacy(TableBase):
1206 u"""The effectiveness of damage of one type against pokémon of another type
1207 """
1208 __tablename__ = 'type_efficacy'
1209 damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1210 info=dict(description=u"ID of the damage type; most commonly this is the same as the attack type"))
1211 target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1212 info=dict(description=u"ID of the defending pokémon's type"))
1213 damage_factor = Column(Integer, nullable=False,
1214 info=dict(description=u"The effectiveness, in percent"))
1215
1216 class Type(TableBase):
1217 u"""An elemental type, such as Grass or Steel
1218 """
1219 __tablename__ = 'types'
1220 __singlename__ = 'type'
1221 id = Column(Integer, primary_key=True, nullable=False,
1222 info=dict(description=u"A numeric ID"))
1223 name = Column(Unicode(8), nullable=False,
1224 info=dict(description=u"The English name.", format='plaintext')) # XXX: Is this official? The games don't spell "Electric" in full...
1225 abbreviation = Column(Unicode(3), nullable=False,
1226 info=dict(description=u"An arbitrary 3-letter abbreviation of the type", format='plaintext')) # XXX: Or is it not arbitrary?
1227 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
1228 info=dict(description=u"ID of the generation this type first appeared in"))
1229 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False,
1230 info=dict(description=u"ID of the damage class this type's moves had before generation IV, or None for the ??? type"))
1231
1232 class TypeName(TableBase):
1233 u"""Non-English name of an elemental type
1234 """
1235 __tablename__ = 'type_names'
1236 type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1237 info=dict(description=u"ID of the type"))
1238 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
1239 info=dict(description=u"ID of the language"))
1240 name = Column(Unicode(16), nullable=False,
1241 info=dict(description=u"Name of the type in that language", foreign=True, format='plaintext'))
1242
1243 class VersionGroup(TableBase):
1244 u"""A group of related game versions
1245 """
1246 __tablename__ = 'version_groups'
1247 id = Column(Integer, primary_key=True, nullable=False,
1248 info=dict(description=u"A numeric ID"))
1249 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
1250 info=dict(description=u"ID of the generation the games of this group belong to"))
1251 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), nullable=False,
1252 info=dict(description=u"ID of the regional Pokédex used in this version group."))
1253
1254 class VersionGroupRegion(TableBase):
1255 u"""Maps a region to a game version group that features it
1256 """
1257 __tablename__ = 'version_group_regions'
1258 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
1259 info=dict(description=u"ID of the version"))
1260 region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
1261 info=dict(description=u"ID of the region"))
1262
1263 class Version(TableBase):
1264 u"""A version of a mainline pokémon game
1265 """
1266 __tablename__ = 'versions'
1267 id = Column(Integer, primary_key=True, nullable=False,
1268 info=dict(description=u"A numeric ID"))
1269 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
1270 info=dict(description=u"ID of the version group this game belongs to"))
1271 name = Column(Unicode(32), nullable=False,
1272 info=dict(description=u'The English name of the game, without the "Pokémon" prefix', official=True, format='plaintext'))
1273
1274
1275 ### Relations down here, to avoid ordering problems
1276 Ability.flavor_text = relation(AbilityFlavorText, order_by=AbilityFlavorText.version_group_id, backref='ability')
1277 Ability.foreign_names = relation(AbilityName, backref='ability')
1278 Ability.generation = relation(Generation, backref='abilities')
1279 Ability.pokemon = relation(Pokemon,
1280 secondary=PokemonAbility.__table__,
1281 )
1282
1283 AbilityFlavorText.version_group = relation(VersionGroup)
1284
1285 AbilityName.language = relation(Language)
1286
1287 Berry.berry_firmness = relation(BerryFirmness, backref='berries')
1288 Berry.firmness = association_proxy('berry_firmness', 'name')
1289 Berry.flavors = relation(BerryFlavor, order_by=BerryFlavor.contest_type_id, backref='berry')
1290 Berry.natural_gift_type = relation(Type)
1291
1292 BerryFlavor.contest_type = relation(ContestType)
1293
1294 ContestCombo.first = relation(Move, primaryjoin=ContestCombo.first_move_id==Move.id,
1295 backref='contest_combo_first')
1296 ContestCombo.second = relation(Move, primaryjoin=ContestCombo.second_move_id==Move.id,
1297 backref='contest_combo_second')
1298
1299 Encounter.location_area = relation(LocationArea, backref='encounters')
1300 Encounter.pokemon = relation(Pokemon, backref='encounters')
1301 Encounter.version = relation(Version, backref='encounters')
1302 Encounter.slot = relation(EncounterSlot, backref='encounters')
1303
1304 EncounterConditionValue.condition = relation(EncounterCondition, backref='values')
1305
1306 Encounter.condition_value_map = relation(EncounterConditionValueMap, backref='encounter')
1307 Encounter.condition_values = association_proxy('condition_value_map', 'condition_value')
1308 EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
1309 backref='encounter_map')
1310
1311 EncounterSlot.terrain = relation(EncounterTerrain, backref='slots')
1312
1313 EncounterSlot.condition_map = relation(EncounterSlotCondition, backref='slot')
1314 EncounterSlot.conditions = association_proxy('condition_map', 'condition')
1315 EncounterSlotCondition.condition = relation(EncounterCondition,
1316 backref='slot_map')
1317
1318 EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
1319 EvolutionChain.baby_trigger_item = relation(Item, backref='evolution_chains')
1320
1321 Experience.growth_rate = relation(GrowthRate, backref='experience_table')
1322
1323 Generation.canonical_pokedex = relation(Pokedex, backref='canonical_for_generation')
1324 Generation.versions = relation(Version, secondary=VersionGroup.__table__)
1325 Generation.main_region = relation(Region)
1326
1327 GrowthRate.max_experience_obj = relation(Experience, primaryjoin=and_(Experience.growth_rate_id == GrowthRate.id, Experience.level == 100), uselist=False)
1328 GrowthRate.max_experience = association_proxy('max_experience_obj', 'experience')
1329
1330 Item.berry = relation(Berry, uselist=False, backref='item')
1331 Item.flags = relation(ItemFlag, secondary=ItemFlagMap.__table__)
1332 Item.flavor_text = relation(ItemFlavorText, order_by=ItemFlavorText.version_group_id.asc(), backref='item')
1333 Item.fling_effect = relation(ItemFlingEffect, backref='items')
1334 Item.foreign_names = relation(ItemName, backref='item')
1335 Item.machines = relation(Machine, order_by=Machine.version_group_id.asc())
1336 Item.category = relation(ItemCategory)
1337 Item.pocket = association_proxy('category', 'pocket')
1338
1339 ItemCategory.items = relation(Item, order_by=Item.name)
1340 ItemCategory.pocket = relation(ItemPocket)
1341
1342 ItemFlavorText.version_group = relation(VersionGroup)
1343
1344 ItemInternalID.item = relation(Item, backref='internal_ids')
1345 ItemInternalID.generation = relation(Generation)
1346
1347 ItemName.language = relation(Language)
1348
1349 ItemPocket.categories = relation(ItemCategory, order_by=ItemCategory.name)
1350
1351 Location.region = relation(Region, backref='locations')
1352
1353 LocationArea.location = relation(Location, backref='areas')
1354
1355 LocationInternalID.location = relation(Location, backref='internal_ids')
1356 LocationInternalID.generation = relation(Generation)
1357
1358 Machine.item = relation(Item)
1359 Machine.version_group = relation(VersionGroup)
1360
1361 Move.changelog = relation(MoveChangelog,
1362 order_by=MoveChangelog.changed_in_version_group_id.asc(),
1363 backref='move',
1364 )
1365 Move.contest_effect = relation(ContestEffect, backref='moves')
1366 Move.contest_combo_next = association_proxy('contest_combo_first', 'second')
1367 Move.contest_combo_prev = association_proxy('contest_combo_second', 'first')
1368 Move.contest_type = relation(ContestType, backref='moves')
1369 Move.damage_class = relation(MoveDamageClass, backref='moves')
1370 Move.flags = association_proxy('move_flags', 'flag')
1371 Move.flavor_text = relation(MoveFlavorText, order_by=MoveFlavorText.version_group_id, backref='move')
1372 Move.foreign_names = relation(MoveName, backref='move')
1373 Move.generation = relation(Generation, backref='moves')
1374 Move.machines = relation(Machine, backref='move')
1375 Move.move_effect = relation(MoveEffect, backref='moves')
1376 Move.move_flags = relation(MoveFlag, backref='move')
1377 Move.super_contest_effect = relation(SuperContestEffect, backref='moves')
1378 Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
1379 Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
1380 Move.target = relation(MoveTarget, backref='moves')
1381 Move.type = relation(Type, backref='moves')
1382
1383 Move.effect = markdown.MoveEffectProperty('effect')
1384 Move.short_effect = markdown.MoveEffectProperty('short_effect')
1385
1386 MoveChangelog.changed_in = relation(VersionGroup, backref='move_changelog')
1387
1388 MoveEffect.category_map = relation(MoveEffectCategoryMap)
1389 MoveEffect.categories = association_proxy('category_map', 'category')
1390 MoveEffectCategoryMap.category = relation(MoveEffectCategory)
1391
1392 MoveFlag.flag = relation(MoveFlagType)
1393
1394 MoveFlavorText.version_group = relation(VersionGroup)
1395
1396 MoveName.language = relation(Language)
1397
1398 Nature.foreign_names = relation(NatureName, backref='nature')
1399 Nature.decreased_stat = relation(Stat, primaryjoin=Nature.decreased_stat_id==Stat.id,
1400 backref='decreasing_natures')
1401 Nature.increased_stat = relation(Stat, primaryjoin=Nature.increased_stat_id==Stat.id,
1402 backref='increasing_natures')
1403 Nature.hates_flavor = relation(ContestType, primaryjoin=Nature.hates_flavor_id==ContestType.id,
1404 backref='hating_natures')
1405 Nature.likes_flavor = relation(ContestType, primaryjoin=Nature.likes_flavor_id==ContestType.id,
1406 backref='liking_natures')
1407 Nature.battle_style_preferences = relation(NatureBattleStylePreference,
1408 order_by=NatureBattleStylePreference.move_battle_style_id,
1409 backref='nature')
1410 Nature.pokeathlon_effects = relation(NaturePokeathlonStat, order_by=NaturePokeathlonStat.pokeathlon_stat_id)
1411
1412 NatureBattleStylePreference.battle_style = relation(MoveBattleStyle, backref='nature_preferences')
1413
1414 NatureName.language = relation(Language)
1415
1416 NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat, backref='nature_effects')
1417
1418 Pokedex.region = relation(Region, backref='pokedexes')
1419 Pokedex.version_groups = relation(VersionGroup, order_by=VersionGroup.id, back_populates='pokedex')
1420
1421 Pokemon.all_abilities = relation(Ability,
1422 secondary=PokemonAbility.__table__,
1423 order_by=PokemonAbility.slot,
1424 )
1425 Pokemon.abilities = relation(Ability,
1426 secondary=PokemonAbility.__table__,
1427 primaryjoin=and_(
1428 Pokemon.id == PokemonAbility.pokemon_id,
1429 PokemonAbility.is_dream == False,
1430 ),
1431 order_by=PokemonAbility.slot,
1432 )
1433 Pokemon.dream_ability = relation(Ability,
1434 secondary=PokemonAbility.__table__,
1435 primaryjoin=and_(
1436 Pokemon.id == PokemonAbility.pokemon_id,
1437 PokemonAbility.is_dream == True,
1438 ),
1439 uselist=False,
1440 )
1441 Pokemon.pokemon_color = relation(PokemonColor, backref='pokemon')
1442 Pokemon.color = association_proxy('pokemon_color', 'name')
1443 Pokemon.dex_numbers = relation(PokemonDexNumber, order_by=PokemonDexNumber.pokedex_id.asc(), backref='pokemon')
1444 Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
1445 order_by=PokemonEggGroup.egg_group_id,
1446 backref='pokemon')
1447 Pokemon.evolution_chain = relation(EvolutionChain, backref='pokemon')
1448 Pokemon.child_pokemon = relation(Pokemon,
1449 primaryjoin=Pokemon.id==PokemonEvolution.from_pokemon_id,
1450 secondary=PokemonEvolution.__table__,
1451 secondaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
1452 backref=backref('parent_pokemon', uselist=False),
1453 )
1454 Pokemon.flavor_text = relation(PokemonFlavorText, order_by=PokemonFlavorText.version_id.asc(), backref='pokemon')
1455 Pokemon.foreign_names = relation(PokemonName, backref='pokemon')
1456 Pokemon.forms = relation(PokemonForm, primaryjoin=Pokemon.id==PokemonForm.form_base_pokemon_id,
1457 order_by=(PokemonForm.order.asc(), PokemonForm.name.asc()))
1458 Pokemon.default_form = relation(PokemonForm,
1459 primaryjoin=and_(Pokemon.id==PokemonForm.form_base_pokemon_id, PokemonForm.is_default==True),
1460 uselist=False,
1461 )
1462 Pokemon.pokemon_habitat = relation(PokemonHabitat, backref='pokemon')
1463 Pokemon.habitat = association_proxy('pokemon_habitat', 'name')
1464 Pokemon.items = relation(PokemonItem, backref='pokemon')
1465 Pokemon.generation = relation(Generation, backref='pokemon')
1466 Pokemon.shape = relation(PokemonShape, backref='pokemon')
1467 Pokemon.stats = relation(PokemonStat, backref='pokemon', order_by=PokemonStat.stat_id.asc())
1468 Pokemon.types = relation(Type, secondary=PokemonType.__table__, order_by=PokemonType.slot.asc(), backref='pokemon')
1469
1470 PokemonDexNumber.pokedex = relation(Pokedex)
1471
1472 PokemonEvolution.from_pokemon = relation(Pokemon,
1473 primaryjoin=PokemonEvolution.from_pokemon_id==Pokemon.id,
1474 backref='child_evolutions',
1475 )
1476 PokemonEvolution.to_pokemon = relation(Pokemon,
1477 primaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
1478 backref=backref('parent_evolution', uselist=False),
1479 )
1480 PokemonEvolution.child_evolutions = relation(PokemonEvolution,
1481 primaryjoin=PokemonEvolution.from_pokemon_id==PokemonEvolution.to_pokemon_id,
1482 foreign_keys=[PokemonEvolution.to_pokemon_id],
1483 backref=backref('parent_evolution',
1484 remote_side=[PokemonEvolution.from_pokemon_id],
1485 uselist=False,
1486 ),
1487 )
1488 PokemonEvolution.trigger = relation(EvolutionTrigger, backref='evolutions')
1489 PokemonEvolution.trigger_item = relation(Item,
1490 primaryjoin=PokemonEvolution.trigger_item_id==Item.id,
1491 backref='triggered_evolutions',
1492 )
1493 PokemonEvolution.held_item = relation(Item,
1494 primaryjoin=PokemonEvolution.held_item_id==Item.id,
1495 backref='required_for_evolutions',
1496 )
1497 PokemonEvolution.location = relation(Location, backref='triggered_evolutions')
1498 PokemonEvolution.known_move = relation(Move, backref='triggered_evolutions')
1499 PokemonEvolution.party_pokemon = relation(Pokemon,
1500 primaryjoin=PokemonEvolution.party_pokemon_id==Pokemon.id,
1501 backref='triggered_evolutions',
1502 )
1503
1504 PokemonFlavorText.version = relation(Version)
1505
1506 PokemonForm.form_base_pokemon = relation(Pokemon, primaryjoin=PokemonForm.form_base_pokemon_id==Pokemon.id)
1507 PokemonForm.unique_pokemon = relation(Pokemon, backref=backref('unique_form', uselist=False),
1508 primaryjoin=PokemonForm.unique_pokemon_id==Pokemon.id)
1509 PokemonForm.version_group = relation(VersionGroup)
1510 PokemonForm.form_group = association_proxy('form_base_pokemon', 'form_group')
1511 PokemonForm.pokeathlon_stats = relation(PokemonFormPokeathlonStat,
1512 order_by=PokemonFormPokeathlonStat.pokeathlon_stat_id,
1513 backref='pokemon_form')
1514
1515 PokemonFormGroup.pokemon = relation(Pokemon, backref=backref('form_group',
1516 uselist=False))
1517
1518 PokemonFormPokeathlonStat.pokeathlon_stat = relation(PokeathlonStat)
1519
1520 PokemonItem.item = relation(Item, backref='pokemon')
1521 PokemonItem.version = relation(Version)
1522
1523 PokemonMove.pokemon = relation(Pokemon, backref='pokemon_moves')
1524 PokemonMove.version_group = relation(VersionGroup)
1525 PokemonMove.machine = relation(Machine, backref='pokemon_moves',
1526 primaryjoin=and_(Machine.version_group_id==PokemonMove.version_group_id,
1527 Machine.move_id==PokemonMove.move_id),
1528 foreign_keys=[Machine.version_group_id, Machine.move_id],
1529 uselist=False)
1530 PokemonMove.move = relation(Move, backref='pokemon_moves')
1531 PokemonMove.method = relation(PokemonMoveMethod)
1532
1533 PokemonName.language = relation(Language)
1534
1535 PokemonStat.stat = relation(Stat)
1536
1537 # This is technically a has-many; Generation.main_region_id -> Region.id
1538 Region.generation = relation(Generation, uselist=False)
1539 Region.version_group_regions = relation(VersionGroupRegion, backref='region',
1540 order_by='VersionGroupRegion.version_group_id')
1541 Region.version_groups = association_proxy('version_group_regions', 'version_group')
1542
1543 Stat.damage_class = relation(MoveDamageClass, backref='stats')
1544
1545 SuperContestCombo.first = relation(Move, primaryjoin=SuperContestCombo.first_move_id==Move.id,
1546 backref='super_contest_combo_first')
1547 SuperContestCombo.second = relation(Move, primaryjoin=SuperContestCombo.second_move_id==Move.id,
1548 backref='super_contest_combo_second')
1549
1550 Type.damage_efficacies = relation(TypeEfficacy,
1551 primaryjoin=Type.id
1552 ==TypeEfficacy.damage_type_id,
1553 backref='damage_type')
1554 Type.target_efficacies = relation(TypeEfficacy,
1555 primaryjoin=Type.id
1556 ==TypeEfficacy.target_type_id,
1557 backref='target_type')
1558
1559 Type.generation = relation(Generation, backref='types')
1560 Type.damage_class = relation(MoveDamageClass, backref='types')
1561 Type.foreign_names = relation(TypeName, backref='type')
1562
1563 TypeName.language = relation(Language)
1564
1565 Version.version_group = relation(VersionGroup, backref='versions')
1566 Version.generation = association_proxy('version_group', 'generation')
1567
1568 VersionGroup.generation = relation(Generation, backref='version_groups')
1569 VersionGroup.version_group_regions = relation(VersionGroupRegion, backref='version_group')
1570 VersionGroup.regions = association_proxy('version_group_regions', 'region')
1571 VersionGroup.pokedex = relation(Pokedex, back_populates='version_groups')