Support kaburumo and chobomaki's trade-for-each other evolution. #378
[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 order = Column(Integer, nullable=False, index=True,
845 info=dict(description=u"Order for sorting. Almost national order, except families and forms are grouped together."))
846
847 ### Stuff to handle alternate Pokémon forms
848
849 @property
850 def is_base_form(self):
851 u"""Returns True iff the Pokémon is the base form for its species,
852 e.g. Land Shaymin.
853 """
854
855 return self.unique_form is None or self.unique_form.is_default
856
857 @property
858 def form_name(self):
859 u"""Returns the Pokémon's form name if it represents a particular form
860 and that form has a name, or None otherwise.
861 """
862
863 # If self.unique_form is None, the short-circuit "and" will go ahead
864 # and return that. Otherwise, it'll return the form's name, which may
865 # also be None.
866 return self.unique_form and self.unique_form.name
867
868 @property
869 def full_name(self):
870 u"""Returns the Pokémon's name, including its form if applicable."""
871
872 if self.form_name:
873 return '{0} {1}'.format(self.form_name, self.name)
874 else:
875 return self.name
876
877 @property
878 def normal_form(self):
879 u"""Returns the normal form for this Pokémon; i.e., this will return
880 regular Deoxys when called on any Deoxys form.
881 """
882
883 if self.unique_form:
884 return self.unique_form.form_base_pokemon
885 return self
886
887 ### Not forms!
888
889 def stat(self, stat_name):
890 u"""Returns a PokemonStat record for the given stat name (or Stat row
891 object). Uses the normal has-many machinery, so all the stats are
892 effectively cached.
893 """
894 if isinstance(stat_name, Stat):
895 stat_name = stat_name.name
896
897 for pokemon_stat in self.stats:
898 if pokemon_stat.stat.name == stat_name:
899 return pokemon_stat
900
901 raise KeyError(u'No stat named %s' % stat_name)
902
903 @property
904 def better_damage_class(self):
905 u"""Returns the MoveDamageClass that this Pokémon is best suited for,
906 based on its attack stats.
907
908 If the attack stats are about equal (within 5), returns None. The
909 value None, not the damage class called 'None'.
910 """
911 phys = self.stat(u'Attack')
912 spec = self.stat(u'Special Attack')
913
914 diff = phys.base_stat - spec.base_stat
915
916 if diff > 5:
917 return phys.stat.damage_class
918 elif diff < -5:
919 return spec.stat.damage_class
920 else:
921 return None
922
923 class PokemonAbility(TableBase):
924 u"""Maps an ability to a pokémon that can have it
925 """
926 __tablename__ = 'pokemon_abilities'
927 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
928 info=dict(description=u"ID of the pokémon"))
929 ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
930 info=dict(description=u"ID of the ability"))
931 # XXX having both a method and a slot is kind of gross. "slot" is a
932 # misnomer, anyway: duplicate abilities don't appear in slot 2.
933 # Probably should replace that with "order".
934 is_dream = Column(Boolean, nullable=False, index=True,
935 info=dict(description=u"Whether this is a Dream World ability"))
936 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
937 info=dict(description=u"The ability slot, i.e. 1 or 2 for gen. IV"))
938
939 class PokemonColor(TableBase):
940 u"""The "pokédex color" of a pokémon species. Usually based on the pokémon's color.
941 """
942 __tablename__ = 'pokemon_colors'
943 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
944 info=dict(description=u"ID of the pokémon"))
945 name = Column(Unicode(6), nullable=False,
946 info=dict(description=u"The English name of the color", official=True, format='identifier'))
947
948 class PokemonDexNumber(TableBase):
949 u"""The number of a Pokémon in a particular Pokédex (e.g. Jigglypuff is #138 in Hoenn's 'dex)
950 """
951 __tablename__ = 'pokemon_dex_numbers'
952 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
953 info=dict(description=u"ID of the pokémon"))
954 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), primary_key=True, nullable=False, autoincrement=False,
955 info=dict(description=u"ID of the pokédex"))
956 pokedex_number = Column(Integer, nullable=False,
957 info=dict(description=u"Number of the pokémon in that the pokédex"))
958
959 class PokemonEggGroup(TableBase):
960 u"""Maps an Egg group to a pokémon; each pokémon belongs to one or two egg groups
961 """
962 __tablename__ = 'pokemon_egg_groups'
963 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
964 info=dict(description=u"ID of the pokémon"))
965 egg_group_id = Column(Integer, ForeignKey('egg_groups.id'), primary_key=True, nullable=False, autoincrement=False,
966 info=dict(description=u"ID of the egg group"))
967
968 class PokemonEvolution(TableBase):
969 u"""Specifies what causes a particular pokémon to evolve into another species.
970 """
971 __tablename__ = 'pokemon_evolution'
972 from_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False,
973 info=dict(description=u"ID of the pre-evolution species"))
974 to_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
975 info=dict(description=u"ID of the post-evolution species"))
976 evolution_trigger_id = Column(Integer, ForeignKey('evolution_triggers.id'), nullable=False,
977 info=dict(description=u"ID of the trigger type"))
978 trigger_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
979 info=dict(description=u"ID of the item that triggers the evolution in a way defined by evolution_trigger_id"))
980 minimum_level = Column(Integer, nullable=True,
981 info=dict(description=u"Minimum level, or None if level doean't matter"))
982 gender = Column(Enum('male', 'female', name='pokemon_evolution_gender'), nullable=True,
983 info=dict(description=u"Required gender, or None if gender doesn't matter"))
984 location_id = Column(Integer, ForeignKey('locations.id'), nullable=True,
985 info=dict(description=u"Required location, or None if it doesn't matter"))
986 held_item_id = Column(Integer, ForeignKey('items.id'), nullable=True,
987 info=dict(description=u"An item the pokémon must hold, or None if it doesn't matter"))
988 time_of_day = Column(Enum('morning', 'day', 'night', name='pokemon_evolution_time_of_day'), nullable=True,
989 info=dict(description=u"Required time of day, or None if it doesn't matter"))
990 known_move_id = Column(Integer, ForeignKey('moves.id'), nullable=True,
991 info=dict(description=u"ID of a move the pokémon must know, or None if it doesn't matter"))
992 minimum_happiness = Column(Integer, nullable=True,
993 info=dict(description=u"Minimum tameness value the pokémon must have, or None if it doesn't matter"))
994 minimum_beauty = Column(Integer, nullable=True,
995 info=dict(description=u"Minimum Beauty value the pokémon must have, or None if it doesn't matter"))
996 relative_physical_stats = Column(Integer, nullable=True,
997 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"))
998 party_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True,
999 info=dict(description=u"The ID of the Pokémon that must be present in the party."))
1000 trade_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True,
1001 info=dict(description=u"The ID of the Pokémon for which this Pokémon must be traded."))
1002
1003 class PokemonFlavorText(TableBase):
1004 u"""In-game pokédex descrption of a pokémon.
1005 """
1006 __tablename__ = 'pokemon_flavor_text'
1007 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1008 info=dict(description=u"ID of the pokémon"))
1009 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
1010 info=dict(description=u"ID of the version that has this flavor text"))
1011 flavor_text = Column(Unicode(255), nullable=False,
1012 info=dict(description=u"ID of the version that has this flavor text", official=True, format='gametext'))
1013
1014 class PokemonForm(TableBase):
1015 u"""An individual form of a Pokémon.
1016
1017 Pokémon that do not have separate forms are still given a single row to
1018 represent their single form.
1019 """
1020 __tablename__ = 'pokemon_forms'
1021 __singlename__ = 'pokemon_form'
1022 id = Column(Integer, primary_key=True, nullable=False,
1023 info=dict(description=u'A unique ID for this form.'))
1024 name = Column(Unicode(16), nullable=True,
1025 info=dict(description=u"This form's name, e.g. \"Plant\" for Plant Cloak Burmy.", official=True, format='plaintext'))
1026 form_base_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
1027 info=dict(description=u'The ID of the base Pokémon for this form.'))
1028 unique_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), autoincrement=False,
1029 info=dict(description=u'The ID of a Pokémon that represents specifically this form, for Pokémon with functionally-different forms like Wormadam.'))
1030 introduced_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), autoincrement=False,
1031 info=dict(description=u'The ID of the version group in which this form first appeared.'))
1032 is_default = Column(Boolean, nullable=False,
1033 info=dict(description=u'Set for exactly one form used as the default for each species.'))
1034 order = Column(Integer, nullable=False, autoincrement=False,
1035 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.'))
1036
1037 @property
1038 def full_name(self):
1039 u"""Returns the full name of this form, e.g. "Plant Cloak"."""
1040
1041 if not self.name:
1042 return None
1043 elif self.form_group and self.form_group.term:
1044 return '{0} {1}'.format(self.name, self.form_group.term)
1045 else:
1046 return self.name
1047
1048 @property
1049 def pokemon_name(self):
1050 u"""Returns the name of this Pokémon with this form, e.g. "Plant
1051 Burmy".
1052 """
1053
1054 if self.name:
1055 return '{0} {1}'.format(self.name, self.form_base_pokemon.name)
1056 else:
1057 return self.form_base_pokemon.name
1058
1059 class PokemonFormGroup(TableBase):
1060 u"""Information about a Pokémon's forms as a group."""
1061 __tablename__ = 'pokemon_form_groups'
1062 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1063 info=dict(description=u"ID of the base form Pokémon"))
1064 term = Column(Unicode(16), nullable=True,
1065 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'))
1066 is_battle_only = Column(Boolean, nullable=False,
1067 info=dict(description=u"Set iff the forms only change in battle"))
1068 description = Column(markdown.MarkdownColumn(1024), nullable=False,
1069 info=dict(description=u"English description of how the forms work", format='markdown'))
1070
1071 class PokemonFormPokeathlonStat(TableBase):
1072 u"""A Pokémon form's performance in one Pokéathlon stat."""
1073 __tablename__ = 'pokemon_form_pokeathlon_stats'
1074 pokemon_form_id = Column(Integer, ForeignKey('pokemon_forms.id'), primary_key=True, nullable=False, autoincrement=False,
1075 info=dict(description=u'The ID of the Pokémon form.'))
1076 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False, autoincrement=False,
1077 info=dict(description=u'The ID of the Pokéathlon stat.'))
1078 minimum_stat = Column(Integer, nullable=False, autoincrement=False,
1079 info=dict(description=u'The minimum value for this stat for this Pokémon form.'))
1080 base_stat = Column(Integer, nullable=False, autoincrement=False,
1081 info=dict(description=u'The default value for this stat for this Pokémon form.'))
1082 maximum_stat = Column(Integer, nullable=False, autoincrement=False,
1083 info=dict(description=u'The maximum value for this stat for this Pokémon form.'))
1084
1085 class PokemonHabitat(TableBase):
1086 u"""The habitat of a pokémon, as given in the FireRed/LeafGreen version pokédex
1087 """
1088 __tablename__ = 'pokemon_habitats'
1089 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1090 info=dict(description=u"A numeric ID"))
1091 name = Column(Unicode(16), nullable=False,
1092 info=dict(description=u"The English name of the habitat", official=True, format='plaintext'))
1093
1094 class PokemonInternalID(TableBase):
1095 u"""The number of a pokémon a game uses internally
1096 """
1097 __tablename__ = 'pokemon_internal_ids'
1098 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False,
1099 info=dict(description=u"Database ID of the pokémon"))
1100 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
1101 info=dict(description=u"Database ID of the generation"))
1102 internal_id = Column(Integer, nullable=False,
1103 info=dict(description=u"Internal ID the generation's games use for the pokémon"))
1104
1105 class PokemonItem(TableBase):
1106 u"""Record of an item a pokémon can hold in the wild
1107 """
1108 __tablename__ = 'pokemon_items'
1109 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1110 info=dict(description=u"ID of the pokémon"))
1111 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
1112 info=dict(description=u"ID of the version this applies to"))
1113 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, nullable=False, autoincrement=False,
1114 info=dict(description=u"ID of the item"))
1115 rarity = Column(Integer, nullable=False,
1116 info=dict(description=u"Chance of the pokémon holding the item, in percent"))
1117
1118 class PokemonMove(TableBase):
1119 u"""Record of a move a pokémon can learn
1120 """
1121 __tablename__ = 'pokemon_moves'
1122 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, index=True,
1123 info=dict(description=u"ID of the pokémon"))
1124 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, index=True,
1125 info=dict(description=u"ID of the version group this applies to"))
1126 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False, index=True,
1127 info=dict(description=u"ID of the move"))
1128 pokemon_move_method_id = Column(Integer, ForeignKey('pokemon_move_methods.id'), nullable=False, index=True,
1129 info=dict(description=u"ID of the method this move is learned by"))
1130 level = Column(Integer, nullable=True, index=True,
1131 info=dict(description=u"Level the move is learned at, if applicable"))
1132 order = Column(Integer, nullable=True,
1133 info=dict(description=u"A sort key to produce the correct ordering when all else is equal")) # XXX: This needs a better description
1134
1135 __table_args__ = (
1136 PrimaryKeyConstraint('pokemon_id', 'version_group_id', 'move_id', 'pokemon_move_method_id', 'level'),
1137 {},
1138 )
1139
1140 class PokemonMoveMethod(TableBase):
1141 u"""A method a move can be learned by, such as "Level up" or "Tutor".
1142 """
1143 __tablename__ = 'pokemon_move_methods'
1144 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1145 info=dict(description=u"A numeric ID"))
1146 name = Column(Unicode(64), nullable=False,
1147 info=dict(description=u"An English name of the method", format='plaintext'))
1148 description = Column(Unicode(255), nullable=False,
1149 info=dict(description=u"A detailed description of how the method works", format='plaintext'))
1150
1151 class PokemonName(TableBase):
1152 u"""A non-English name of a pokémon.
1153 """
1154 __tablename__ = 'pokemon_names'
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 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
1158 info=dict(description=u"ID of the language"))
1159 name = Column(Unicode(16), nullable=False,
1160 info=dict(description=u"Name of the pokémon in the language", foreign=True, format='plaintext'))
1161
1162 class PokemonShape(TableBase):
1163 u"""The shape of a pokémon's body, as used in generation IV pokédexes.
1164 """
1165 __tablename__ = 'pokemon_shapes'
1166 id = Column(Integer, primary_key=True, nullable=False,
1167 info=dict(description=u"A numeric ID"))
1168 name = Column(Unicode(24), nullable=False,
1169 info=dict(description=u"A boring English name of the body shape", format='plaintext'))
1170 awesome_name = Column(Unicode(16), nullable=False,
1171 info=dict(description=u"A splendiferous, technically English, name of the body shape", format='plaintext'))
1172
1173 class PokemonStat(TableBase):
1174 u"""A stat value of a pokémon
1175 """
1176 __tablename__ = 'pokemon_stats'
1177 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1178 info=dict(description=u"ID of the pokémon"))
1179 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False,
1180 info=dict(description=u"ID of the stat"))
1181 base_stat = Column(Integer, nullable=False,
1182 info=dict(description=u"The base stat"))
1183 effort = Column(Integer, nullable=False,
1184 info=dict(description=u"The effort increase in this stat gained when this pokémon is defeated"))
1185
1186 class PokemonType(TableBase):
1187 u"""Maps a type to a pokémon. Each pokémon has 1 or 2 types.
1188 """
1189 __tablename__ = 'pokemon_types'
1190 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
1191 info=dict(description=u"ID of the pokémon"))
1192 type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
1193 info=dict(description=u"ID of the type"))
1194 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
1195 info=dict(description=u"The type's slot, 1 or 2, used to sort types if there are two of them"))
1196
1197 class Region(TableBase):
1198 u"""Major areas of the world: Kanto, Johto, etc.
1199 """
1200 __tablename__ = 'regions'
1201 id = Column(Integer, primary_key=True, nullable=False,
1202 info=dict(description=u"A numeric ID"))
1203 name = Column(Unicode(16), nullable=False,
1204 info=dict(description=u"The English name of the region", official=True, format='plaintext'))
1205
1206 class Stat(TableBase):
1207 u"""A Stat, such as Attack or Speed
1208 """
1209 __tablename__ = 'stats'
1210 id = Column(Integer, primary_key=True, nullable=False,
1211 info=dict(description=u"A numeric ID"))
1212 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True,
1213 info=dict(description=u"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
1214 name = Column(Unicode(16), nullable=False,
1215 info=dict(description=u"The English name of the stat", official=True, format='plaintext'))
1216
1217 class SuperContestCombo(TableBase):
1218 u"""Combo of two moves in a Super Contest.
1219 """
1220 __tablename__ = 'super_contest_combos'
1221 first_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
1222 info=dict(description=u"ID of the first move"))
1223 second_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
1224 info=dict(description=u"ID of the second and last move"))
1225
1226 class SuperContestEffect(TableBase):
1227 u"""An effect a move can have when used in the Super Contest
1228 """
1229 __tablename__ = 'super_contest_effects'
1230 id = Column(Integer, primary_key=True, nullable=False,
1231 info=dict(description=u"A numeric ID"))
1232 appeal = Column(SmallInteger, nullable=False,
1233 info=dict(description=u"Number of hearts the user will get when executing a move with this effect"))
1234 flavor_text = Column(Unicode(64), nullable=False,
1235 info=dict(description=u"An English description of the effect", format='plaintext'))
1236
1237 class TypeEfficacy(TableBase):
1238 u"""The effectiveness of damage of one type against pokémon of another type
1239 """
1240 __tablename__ = 'type_efficacy'
1241 damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1242 info=dict(description=u"ID of the damage type; most commonly this is the same as the attack type"))
1243 target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1244 info=dict(description=u"ID of the defending pokémon's type"))
1245 damage_factor = Column(Integer, nullable=False,
1246 info=dict(description=u"The effectiveness, in percent"))
1247
1248 class Type(TableBase):
1249 u"""An elemental type, such as Grass or Steel
1250 """
1251 __tablename__ = 'types'
1252 __singlename__ = 'type'
1253 id = Column(Integer, primary_key=True, nullable=False,
1254 info=dict(description=u"A numeric ID"))
1255 name = Column(Unicode(8), nullable=False,
1256 info=dict(description=u"The English name.", format='plaintext')) # XXX: Is this official? The games don't spell "Electric" in full...
1257 abbreviation = Column(Unicode(3), nullable=False,
1258 info=dict(description=u"An arbitrary 3-letter abbreviation of the type", format='plaintext')) # XXX: Or is it not arbitrary?
1259 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
1260 info=dict(description=u"ID of the generation this type first appeared in"))
1261 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False,
1262 info=dict(description=u"ID of the damage class this type's moves had before generation IV, or None for the ??? type"))
1263
1264 class TypeName(TableBase):
1265 u"""Non-English name of an elemental type
1266 """
1267 __tablename__ = 'type_names'
1268 type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
1269 info=dict(description=u"ID of the type"))
1270 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
1271 info=dict(description=u"ID of the language"))
1272 name = Column(Unicode(16), nullable=False,
1273 info=dict(description=u"Name of the type in that language", foreign=True, format='plaintext'))
1274
1275 class VersionGroup(TableBase):
1276 u"""A group of related game versions
1277 """
1278 __tablename__ = 'version_groups'
1279 id = Column(Integer, primary_key=True, nullable=False,
1280 info=dict(description=u"A numeric ID"))
1281 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
1282 info=dict(description=u"ID of the generation the games of this group belong to"))
1283 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), nullable=False,
1284 info=dict(description=u"ID of the regional Pokédex used in this version group."))
1285
1286 class VersionGroupRegion(TableBase):
1287 u"""Maps a region to a game version group that features it
1288 """
1289 __tablename__ = 'version_group_regions'
1290 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
1291 info=dict(description=u"ID of the version"))
1292 region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
1293 info=dict(description=u"ID of the region"))
1294
1295 class Version(TableBase):
1296 u"""An individual main-series Pokémon game
1297 """
1298 __tablename__ = 'versions'
1299 id = Column(Integer, primary_key=True, nullable=False,
1300 info=dict(description=u"A unique ID for this version"))
1301 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
1302 info=dict(description=u"The ID of the version group this game belongs to"))
1303 name = Column(Unicode(32), nullable=False,
1304 info=dict(description=u'The English name of the game, without the "Pokémon" prefix', official=True, format='plaintext'))
1305
1306
1307 ### Relations down here, to avoid ordering problems
1308 Ability.changelog = relation(AbilityChangelog,
1309 order_by=AbilityChangelog.changed_in_version_group_id.desc(),
1310 backref='ability',
1311 )
1312 Ability.flavor_text = relation(AbilityFlavorText, order_by=AbilityFlavorText.version_group_id, backref='ability')
1313 Ability.foreign_names = relation(AbilityName, backref='ability')
1314 Ability.generation = relation(Generation, backref='abilities')
1315 Ability.all_pokemon = relation(Pokemon,
1316 secondary=PokemonAbility.__table__,
1317 back_populates='all_abilities',
1318 )
1319 Ability.pokemon = relation(Pokemon,
1320 secondary=PokemonAbility.__table__,
1321 primaryjoin=and_(
1322 PokemonAbility.ability_id == Ability.id,
1323 PokemonAbility.is_dream == False
1324 ),
1325 back_populates='abilities',
1326 )
1327 Ability.dream_pokemon = relation(Pokemon,
1328 secondary=PokemonAbility.__table__,
1329 primaryjoin=and_(
1330 PokemonAbility.ability_id == Ability.id,
1331 PokemonAbility.is_dream == True
1332 ),
1333 back_populates='dream_ability',
1334 )
1335
1336 AbilityChangelog.changed_in = relation(VersionGroup, backref='ability_changelog')
1337
1338 AbilityFlavorText.version_group = relation(VersionGroup)
1339
1340 AbilityName.language = relation(Language)
1341
1342 Berry.berry_firmness = relation(BerryFirmness, backref='berries')
1343 Berry.firmness = association_proxy('berry_firmness', 'name')
1344 Berry.flavors = relation(BerryFlavor, order_by=BerryFlavor.contest_type_id, backref='berry')
1345 Berry.natural_gift_type = relation(Type)
1346
1347 BerryFlavor.contest_type = relation(ContestType)
1348
1349 ContestCombo.first = relation(Move, primaryjoin=ContestCombo.first_move_id==Move.id,
1350 backref='contest_combo_first')
1351 ContestCombo.second = relation(Move, primaryjoin=ContestCombo.second_move_id==Move.id,
1352 backref='contest_combo_second')
1353
1354 Encounter.location_area = relation(LocationArea, backref='encounters')
1355 Encounter.pokemon = relation(Pokemon, backref='encounters')
1356 Encounter.version = relation(Version, backref='encounters')
1357 Encounter.slot = relation(EncounterSlot, backref='encounters')
1358
1359 EncounterConditionValue.condition = relation(EncounterCondition, backref='values')
1360
1361 Encounter.condition_value_map = relation(EncounterConditionValueMap, backref='encounter')
1362 Encounter.condition_values = association_proxy('condition_value_map', 'condition_value')
1363 EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
1364 backref='encounter_map')
1365
1366 EncounterSlot.terrain = relation(EncounterTerrain, backref='slots')
1367
1368 EncounterSlot.condition_map = relation(EncounterSlotCondition, backref='slot')
1369 EncounterSlot.conditions = association_proxy('condition_map', 'condition')
1370 EncounterSlotCondition.condition = relation(EncounterCondition,
1371 backref='slot_map')
1372
1373 EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
1374 EvolutionChain.baby_trigger_item = relation(Item, backref='evolution_chains')
1375 EvolutionChain.pokemon = relation(Pokemon, order_by=Pokemon.order, back_populates='evolution_chain')
1376
1377 Experience.growth_rate = relation(GrowthRate, backref='experience_table')
1378
1379 Generation.canonical_pokedex = relation(Pokedex, backref='canonical_for_generation')
1380 Generation.versions = relation(Version, secondary=VersionGroup.__table__)
1381 Generation.main_region = relation(Region)
1382
1383 GrowthRate.max_experience_obj = relation(Experience, primaryjoin=and_(Experience.growth_rate_id == GrowthRate.id, Experience.level == 100), uselist=False)
1384 GrowthRate.max_experience = association_proxy('max_experience_obj', 'experience')
1385
1386 Item.berry = relation(Berry, uselist=False, backref='item')
1387 Item.flags = relation(ItemFlag, secondary=ItemFlagMap.__table__)
1388 Item.flavor_text = relation(ItemFlavorText, order_by=ItemFlavorText.version_group_id.asc(), backref='item')
1389 Item.fling_effect = relation(ItemFlingEffect, backref='items')
1390 Item.foreign_names = relation(ItemName, backref='item')
1391 Item.machines = relation(Machine, order_by=Machine.version_group_id.asc())
1392 Item.category = relation(ItemCategory)
1393 Item.pocket = association_proxy('category', 'pocket')
1394
1395 ItemCategory.items = relation(Item, order_by=Item.name)
1396 ItemCategory.pocket = relation(ItemPocket)
1397
1398 ItemFlavorText.version_group = relation(VersionGroup)
1399
1400 ItemInternalID.item = relation(Item, backref='internal_ids')
1401 ItemInternalID.generation = relation(Generation)
1402
1403 ItemName.language = relation(Language)
1404
1405 ItemPocket.categories = relation(ItemCategory, order_by=ItemCategory.name)
1406
1407 Location.region = relation(Region, backref='locations')
1408
1409 LocationArea.location = relation(Location, backref='areas')
1410
1411 LocationInternalID.location = relation(Location, backref='internal_ids')
1412 LocationInternalID.generation = relation(Generation)
1413
1414 Machine.item = relation(Item)
1415 Machine.version_group = relation(VersionGroup)
1416
1417 Move.changelog = relation(MoveChangelog,
1418 order_by=MoveChangelog.changed_in_version_group_id.desc(),
1419 backref='move',
1420 )
1421 Move.contest_effect = relation(ContestEffect, backref='moves')
1422 Move.contest_combo_next = association_proxy('contest_combo_first', 'second')
1423 Move.contest_combo_prev = association_proxy('contest_combo_second', 'first')
1424 Move.contest_type = relation(ContestType, backref='moves')
1425 Move.damage_class = relation(MoveDamageClass, backref='moves')
1426 Move.flags = association_proxy('move_flags', 'flag')
1427 Move.flavor_text = relation(MoveFlavorText, order_by=MoveFlavorText.version_group_id, backref='move')
1428 Move.foreign_names = relation(MoveName, backref='move')
1429 Move.generation = relation(Generation, backref='moves')
1430 Move.machines = relation(Machine, backref='move')
1431 Move.move_effect = relation(MoveEffect, backref='moves')
1432 Move.move_flags = relation(MoveFlag, backref='move')
1433 Move.super_contest_effect = relation(SuperContestEffect, backref='moves')
1434 Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
1435 Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
1436 Move.target = relation(MoveTarget, backref='moves')
1437 Move.type = relation(Type, backref='moves')
1438
1439 Move.effect = markdown.MoveEffectProperty('effect')
1440 Move.short_effect = markdown.MoveEffectProperty('short_effect')
1441
1442 MoveChangelog.changed_in = relation(VersionGroup, backref='move_changelog')
1443 MoveChangelog.move_effect = relation(MoveEffect, backref='move_changelog')
1444 MoveChangelog.type = relation(Type, backref='move_changelog')
1445
1446 MoveChangelog.effect = markdown.MoveEffectProperty('effect')
1447 MoveChangelog.short_effect = markdown.MoveEffectProperty('short_effect')
1448
1449 MoveEffect.category_map = relation(MoveEffectCategoryMap)
1450 MoveEffect.categories = association_proxy('category_map', 'category')
1451 MoveEffectCategoryMap.category = relation(MoveEffectCategory)
1452
1453 MoveFlag.flag = relation(MoveFlagType)
1454
1455 MoveFlavorText.version_group = relation(VersionGroup)
1456
1457 MoveName.language = relation(Language)
1458
1459 Nature.foreign_names = relation(NatureName, backref='nature')
1460 Nature.decreased_stat = relation(Stat, primaryjoin=Nature.decreased_stat_id==Stat.id,
1461 backref='decreasing_natures')
1462 Nature.increased_stat = relation(Stat, primaryjoin=Nature.increased_stat_id==Stat.id,
1463 backref='increasing_natures')
1464 Nature.hates_flavor = relation(ContestType, primaryjoin=Nature.hates_flavor_id==ContestType.id,
1465 backref='hating_natures')
1466 Nature.likes_flavor = relation(ContestType, primaryjoin=Nature.likes_flavor_id==ContestType.id,
1467 backref='liking_natures')
1468 Nature.battle_style_preferences = relation(NatureBattleStylePreference,
1469 order_by=NatureBattleStylePreference.move_battle_style_id,
1470 backref='nature')
1471 Nature.pokeathlon_effects = relation(NaturePokeathlonStat, order_by=NaturePokeathlonStat.pokeathlon_stat_id)
1472
1473 NatureBattleStylePreference.battle_style = relation(MoveBattleStyle, backref='nature_preferences')
1474
1475 NatureName.language = relation(Language)
1476
1477 NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat, backref='nature_effects')
1478
1479 Pokedex.region = relation(Region, backref='pokedexes')
1480 Pokedex.version_groups = relation(VersionGroup, order_by=VersionGroup.id, back_populates='pokedex')
1481
1482 Pokemon.all_abilities = relation(Ability,
1483 secondary=PokemonAbility.__table__,
1484 order_by=PokemonAbility.slot,
1485 )
1486 Pokemon.abilities = relation(Ability,
1487 secondary=PokemonAbility.__table__,
1488 primaryjoin=and_(
1489 Pokemon.id == PokemonAbility.pokemon_id,
1490 PokemonAbility.is_dream == False,
1491 ),
1492 order_by=PokemonAbility.slot,
1493 )
1494 Pokemon.dream_ability = relation(Ability,
1495 secondary=PokemonAbility.__table__,
1496 primaryjoin=and_(
1497 Pokemon.id == PokemonAbility.pokemon_id,
1498 PokemonAbility.is_dream == True,
1499 ),
1500 uselist=False,
1501 )
1502 Pokemon.pokemon_color = relation(PokemonColor, backref='pokemon')
1503 Pokemon.color = association_proxy('pokemon_color', 'name')
1504 Pokemon.dex_numbers = relation(PokemonDexNumber, order_by=PokemonDexNumber.pokedex_id.asc(), backref='pokemon')
1505 Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
1506 order_by=PokemonEggGroup.egg_group_id,
1507 backref=backref('pokemon', order_by=Pokemon.order))
1508 Pokemon.evolution_chain = relation(EvolutionChain, back_populates='pokemon')
1509 Pokemon.child_pokemon = relation(Pokemon,
1510 primaryjoin=Pokemon.id==PokemonEvolution.from_pokemon_id,
1511 secondary=PokemonEvolution.__table__,
1512 secondaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
1513 backref=backref('parent_pokemon', uselist=False),
1514 )
1515 Pokemon.flavor_text = relation(PokemonFlavorText, order_by=PokemonFlavorText.version_id.asc(), backref='pokemon')
1516 Pokemon.foreign_names = relation(PokemonName, backref='pokemon')
1517 Pokemon.forms = relation(PokemonForm, primaryjoin=Pokemon.id==PokemonForm.form_base_pokemon_id,
1518 order_by=(PokemonForm.order.asc(), PokemonForm.name.asc()))
1519 Pokemon.default_form = relation(PokemonForm,
1520 primaryjoin=and_(Pokemon.id==PokemonForm.form_base_pokemon_id, PokemonForm.is_default==True),
1521 uselist=False,
1522 )
1523 Pokemon.pokemon_habitat = relation(PokemonHabitat, backref='pokemon')
1524 Pokemon.habitat = association_proxy('pokemon_habitat', 'name')
1525 Pokemon.items = relation(PokemonItem, backref='pokemon')
1526 Pokemon.generation = relation(Generation, backref='pokemon')
1527 Pokemon.shape = relation(PokemonShape, backref='pokemon')
1528 Pokemon.stats = relation(PokemonStat, backref='pokemon', order_by=PokemonStat.stat_id.asc())
1529 Pokemon.types = relation(Type, secondary=PokemonType.__table__,
1530 order_by=PokemonType.slot.asc(),
1531 back_populates='pokemon')
1532
1533 PokemonDexNumber.pokedex = relation(Pokedex)
1534
1535 PokemonEvolution.from_pokemon = relation(Pokemon,
1536 primaryjoin=PokemonEvolution.from_pokemon_id==Pokemon.id,
1537 backref='child_evolutions',
1538 )
1539 PokemonEvolution.to_pokemon = relation(Pokemon,
1540 primaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
1541 backref=backref('parent_evolution', uselist=False),
1542 )
1543 PokemonEvolution.child_evolutions = relation(PokemonEvolution,
1544 primaryjoin=PokemonEvolution.from_pokemon_id==PokemonEvolution.to_pokemon_id,
1545 foreign_keys=[PokemonEvolution.to_pokemon_id],
1546 backref=backref('parent_evolution',
1547 remote_side=[PokemonEvolution.from_pokemon_id],
1548 uselist=False,
1549 ),
1550 )
1551 PokemonEvolution.trigger = relation(EvolutionTrigger, backref='evolutions')
1552 PokemonEvolution.trigger_item = relation(Item,
1553 primaryjoin=PokemonEvolution.trigger_item_id==Item.id,
1554 backref='triggered_evolutions',
1555 )
1556 PokemonEvolution.held_item = relation(Item,
1557 primaryjoin=PokemonEvolution.held_item_id==Item.id,
1558 backref='required_for_evolutions',
1559 )
1560 PokemonEvolution.location = relation(Location, backref='triggered_evolutions')
1561 PokemonEvolution.known_move = relation(Move, backref='triggered_evolutions')
1562 PokemonEvolution.party_pokemon = relation(Pokemon,
1563 primaryjoin=PokemonEvolution.party_pokemon_id==Pokemon.id,
1564 backref='triggered_evolutions',
1565 )
1566 PokemonEvolution.trade_pokemon = relation(Pokemon,
1567 primaryjoin=PokemonEvolution.trade_pokemon_id==Pokemon.id,
1568 )
1569
1570 PokemonFlavorText.version = relation(Version)
1571
1572 PokemonForm.form_base_pokemon = relation(Pokemon, primaryjoin=PokemonForm.form_base_pokemon_id==Pokemon.id)
1573 PokemonForm.unique_pokemon = relation(Pokemon, backref=backref('unique_form', uselist=False),
1574 primaryjoin=PokemonForm.unique_pokemon_id==Pokemon.id)
1575 PokemonForm.version_group = relation(VersionGroup)
1576 PokemonForm.form_group = association_proxy('form_base_pokemon', 'form_group')
1577 PokemonForm.pokeathlon_stats = relation(PokemonFormPokeathlonStat,
1578 order_by=PokemonFormPokeathlonStat.pokeathlon_stat_id,
1579 backref='pokemon_form')
1580
1581 PokemonFormGroup.pokemon = relation(Pokemon, backref=backref('form_group',
1582 uselist=False))
1583
1584 PokemonFormPokeathlonStat.pokeathlon_stat = relation(PokeathlonStat)
1585
1586 PokemonItem.item = relation(Item, backref='pokemon')
1587 PokemonItem.version = relation(Version)
1588
1589 PokemonMove.pokemon = relation(Pokemon, backref='pokemon_moves')
1590 PokemonMove.version_group = relation(VersionGroup)
1591 PokemonMove.machine = relation(Machine, backref='pokemon_moves',
1592 primaryjoin=and_(Machine.version_group_id==PokemonMove.version_group_id,
1593 Machine.move_id==PokemonMove.move_id),
1594 foreign_keys=[Machine.version_group_id, Machine.move_id],
1595 uselist=False)
1596 PokemonMove.move = relation(Move, backref='pokemon_moves')
1597 PokemonMove.method = relation(PokemonMoveMethod)
1598
1599 PokemonName.language = relation(Language, lazy='joined')
1600
1601 PokemonStat.stat = relation(Stat)
1602
1603 # This is technically a has-many; Generation.main_region_id -> Region.id
1604 Region.generation = relation(Generation, uselist=False)
1605 Region.version_group_regions = relation(VersionGroupRegion, backref='region',
1606 order_by='VersionGroupRegion.version_group_id')
1607 Region.version_groups = association_proxy('version_group_regions', 'version_group')
1608
1609 Stat.damage_class = relation(MoveDamageClass, backref='stats')
1610
1611 SuperContestCombo.first = relation(Move, primaryjoin=SuperContestCombo.first_move_id==Move.id,
1612 backref='super_contest_combo_first')
1613 SuperContestCombo.second = relation(Move, primaryjoin=SuperContestCombo.second_move_id==Move.id,
1614 backref='super_contest_combo_second')
1615
1616 Type.damage_efficacies = relation(TypeEfficacy,
1617 primaryjoin=Type.id
1618 ==TypeEfficacy.damage_type_id,
1619 backref='damage_type')
1620 Type.target_efficacies = relation(TypeEfficacy,
1621 primaryjoin=Type.id
1622 ==TypeEfficacy.target_type_id,
1623 backref='target_type')
1624
1625 Type.generation = relation(Generation, backref='types')
1626 Type.damage_class = relation(MoveDamageClass, backref='types')
1627 Type.foreign_names = relation(TypeName, backref='type')
1628 Type.pokemon = relation(Pokemon, secondary=PokemonType.__table__,
1629 order_by=Pokemon.order,
1630 back_populates='types')
1631
1632 TypeName.language = relation(Language)
1633
1634 Version.version_group = relation(VersionGroup, back_populates='versions')
1635 Version.generation = association_proxy('version_group', 'generation')
1636
1637 VersionGroup.versions = relation(Version, order_by=Version.id, back_populates='version_group')
1638 VersionGroup.generation = relation(Generation, backref='version_groups')
1639 VersionGroup.version_group_regions = relation(VersionGroupRegion, backref='version_group')
1640 VersionGroup.regions = association_proxy('version_group_regions', 'region')
1641 VersionGroup.pokedex = relation(Pokedex, back_populates='version_groups')