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