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