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