Make baby-trigger items (i.e., incense) a foreign key. #337
[zzz-pokedex.git] / pokedex / db / tables.py
1 # encoding: utf8
2
3 from sqlalchemy import Column, ForeignKey, MetaData, Table
4 from sqlalchemy.ext.declarative import declarative_base
5 from sqlalchemy.ext.associationproxy import association_proxy
6 from sqlalchemy.orm import backref, eagerload_all, relation
7 from sqlalchemy.orm.session import Session
8 from sqlalchemy.sql import and_
9 from sqlalchemy.types import *
10
11 from pokedex.db import markdown
12
13 metadata = MetaData()
14 TableBase = declarative_base(metadata=metadata)
15
16 class Ability(TableBase):
17 __tablename__ = 'abilities'
18 __singlename__ = 'ability'
19 id = Column(Integer, primary_key=True, nullable=False)
20 name = Column(Unicode(24), nullable=False)
21 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
22 effect = Column(markdown.MarkdownColumn(5120), nullable=False)
23 short_effect = Column(markdown.MarkdownColumn(255), nullable=False)
24
25 class AbilityFlavorText(TableBase):
26 __tablename__ = 'ability_flavor_text'
27 ability_id = Column(Integer, ForeignKey('abilities.id'), primary_key=True, nullable=False, autoincrement=False)
28 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
29 flavor_text = Column(Unicode(64), nullable=False)
30
31 class AbilityName(TableBase):
32 __tablename__ = 'ability_names'
33 ability_id = Column(Integer, ForeignKey('abilities.id'), primary_key=True, nullable=False, autoincrement=False)
34 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
35 name = Column(Unicode(16), nullable=False)
36
37 class Berry(TableBase):
38 __tablename__ = 'berries'
39 id = Column(Integer, primary_key=True, nullable=False)
40 item_id = Column(Integer, ForeignKey('items.id'), nullable=False)
41 firmness_id = Column(Integer, ForeignKey('berry_firmness.id'), nullable=False)
42 natural_gift_power = Column(Integer, nullable=True)
43 natural_gift_type_id = Column(Integer, ForeignKey('types.id'), nullable=True)
44 size = Column(Integer, nullable=False)
45 max_harvest = Column(Integer, nullable=False)
46 growth_time = Column(Integer, nullable=False)
47 soil_dryness = Column(Integer, nullable=False)
48 smoothness = Column(Integer, nullable=False)
49
50 class BerryFirmness(TableBase):
51 __tablename__ = 'berry_firmness'
52 id = Column(Integer, primary_key=True, nullable=False)
53 name = Column(Unicode(10), nullable=False)
54
55 class BerryFlavor(TableBase):
56 __tablename__ = 'berry_flavors'
57 berry_id = Column(Integer, ForeignKey('berries.id'), primary_key=True, nullable=False, autoincrement=False)
58 contest_type_id = Column(Integer, ForeignKey('contest_types.id'), primary_key=True, nullable=False, autoincrement=False)
59 flavor = Column(Integer, nullable=False)
60
61 class ContestCombo(TableBase):
62 __tablename__ = 'contest_combos'
63 first_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
64 second_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
65
66 class ContestEffect(TableBase):
67 __tablename__ = 'contest_effects'
68 id = Column(Integer, primary_key=True, nullable=False)
69 appeal = Column(SmallInteger, nullable=False)
70 jam = Column(SmallInteger, nullable=False)
71 flavor_text = Column(Unicode(64), nullable=False)
72 effect = Column(Unicode(255), nullable=False)
73
74 class ContestType(TableBase):
75 __tablename__ = 'contest_types'
76 id = Column(Integer, primary_key=True, nullable=False)
77 name = Column(Unicode(6), nullable=False)
78 flavor = Column(Unicode(6), nullable=False)
79 color = Column(Unicode(6), nullable=False)
80
81 class EggGroup(TableBase):
82 __tablename__ = 'egg_groups'
83 id = Column(Integer, primary_key=True, nullable=False)
84 name = Column(Unicode(16), nullable=False)
85
86 class Encounter(TableBase):
87 """Rows in this table represent encounters with wild Pokémon. Bear with
88 me, here.
89
90 Within a given area in a given game, encounters are differentiated by the
91 "slot" they are in and the state of the game world.
92
93 What the player is doing to get an encounter, such as surfing or walking
94 through tall grass, is called terrain. Each terrain has its own set of
95 encounter slots.
96
97 Within a terrain, slots are defined primarily by rarity. Each slot can
98 also be affected by world conditions; for example, the 20% slot for walking
99 in tall grass is affected by whether a swarm is in effect in that area.
100 "Is there a swarm?" is a condition; "there is a swarm" and "there is not a
101 swarm" are the possible values of this condition.
102
103 A slot (20% walking in grass) and any appropriate world conditions (no
104 swarm) are thus enough to define a specific encounter.
105
106 Well, okay, almost: each slot actually appears twice.
107 """
108
109 __tablename__ = 'encounters'
110 id = Column(Integer, primary_key=True, nullable=False)
111 version_id = Column(Integer, ForeignKey('versions.id'), nullable=False, autoincrement=False)
112 location_area_id = Column(Integer, ForeignKey('location_areas.id'), nullable=False, autoincrement=False)
113 encounter_slot_id = Column(Integer, ForeignKey('encounter_slots.id'), nullable=False, autoincrement=False)
114 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False)
115 min_level = Column(Integer, nullable=False, autoincrement=False)
116 max_level = Column(Integer, nullable=False, autoincrement=False)
117
118 class EncounterCondition(TableBase):
119 """Rows in this table represent varying conditions in the game world, such
120 as time of day.
121 """
122
123 __tablename__ = 'encounter_conditions'
124 id = Column(Integer, primary_key=True, nullable=False)
125 name = Column(Unicode(64), nullable=False)
126
127 class EncounterConditionValue(TableBase):
128 """Rows in this table represent possible states for a condition; for
129 example, the state of 'swarm' could be 'swarm' or 'no swarm'.
130 """
131
132 __tablename__ = 'encounter_condition_values'
133 id = Column(Integer, primary_key=True, nullable=False)
134 encounter_condition_id = Column(Integer, ForeignKey('encounter_conditions.id'), primary_key=False, nullable=False, autoincrement=False)
135 name = Column(Unicode(64), nullable=False)
136 is_default = Column(Boolean, nullable=False)
137
138 class EncounterConditionValueMap(TableBase):
139 """Maps encounters to the specific conditions under which they occur."""
140
141 __tablename__ = 'encounter_condition_value_map'
142 encounter_id = Column(Integer, ForeignKey('encounters.id'), primary_key=True, nullable=False, autoincrement=False)
143 encounter_condition_value_id = Column(Integer, ForeignKey('encounter_condition_values.id'), primary_key=True, nullable=False, autoincrement=False)
144
145 class EncounterTerrain(TableBase):
146 """Rows in this table represent ways the player can enter a wild encounter,
147 e.g., surfing, fishing, or walking through tall grass.
148 """
149
150 __tablename__ = 'encounter_terrain'
151 id = Column(Integer, primary_key=True, nullable=False)
152 name = Column(Unicode(64), nullable=False)
153
154 class EncounterSlot(TableBase):
155 """Rows in this table represent an abstract "slot" within a terrain,
156 associated with both some set of conditions and a rarity.
157
158 Note that there are two encounters per slot, so the rarities will only add
159 up to 50.
160 """
161
162 __tablename__ = 'encounter_slots'
163 id = Column(Integer, primary_key=True, nullable=False)
164 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, autoincrement=False)
165 encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=False, nullable=False, autoincrement=False)
166 slot = Column(Integer, nullable=True)
167 rarity = Column(Integer, nullable=False)
168
169 class EncounterSlotCondition(TableBase):
170 """Lists all conditions that affect each slot."""
171
172 __tablename__ = 'encounter_slot_conditions'
173 encounter_slot_id = Column(Integer, ForeignKey('encounter_slots.id'), primary_key=True, nullable=False, autoincrement=False)
174 encounter_condition_id = Column(Integer, ForeignKey('encounter_conditions.id'), primary_key=True, nullable=False, autoincrement=False)
175
176 class EvolutionChain(TableBase):
177 __tablename__ = 'evolution_chains'
178 id = Column(Integer, primary_key=True, nullable=False)
179 growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), nullable=False)
180 baby_trigger_item_id = Column(Integer, ForeignKey('items.id'), nullable=True)
181
182 class EvolutionTrigger(TableBase):
183 __tablename__ = 'evolution_triggers'
184 id = Column(Integer, primary_key=True, nullable=False)
185 identifier = Column(Unicode(16), nullable=False)
186
187 class Experience(TableBase):
188 __tablename__ = 'experience'
189 growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), primary_key=True, nullable=False)
190 level = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
191 experience = Column(Integer, nullable=False)
192
193 class Generation(TableBase):
194 __tablename__ = 'generations'
195 id = Column(Integer, primary_key=True, nullable=False)
196 main_region_id = Column(Integer, ForeignKey('regions.id'))
197 canonical_pokedex_id = Column(Integer, ForeignKey('pokedexes.id'))
198 name = Column(Unicode(16), nullable=False)
199
200 class GrowthRate(TableBase):
201 """`formula` is written in LaTeX math notation."""
202 __tablename__ = 'growth_rates'
203 id = Column(Integer, primary_key=True, nullable=False)
204 name = Column(Unicode(20), nullable=False)
205 formula = Column(Unicode(500), nullable=False)
206
207 class Item(TableBase):
208 __tablename__ = 'items'
209 __singlename__ = 'item'
210 id = Column(Integer, primary_key=True, nullable=False)
211 name = Column(Unicode(16), nullable=False)
212 category_id = Column(Integer, ForeignKey('item_categories.id'), nullable=False)
213 cost = Column(Integer, nullable=False)
214 fling_power = Column(Integer, nullable=True)
215 fling_effect_id = Column(Integer, ForeignKey('item_fling_effects.id'), nullable=True)
216 effect = Column(markdown.MarkdownColumn(5120), nullable=False)
217
218 @property
219 def appears_underground(self):
220 return any(flag.identifier == u'underground' for flag in self.flags)
221
222 class ItemCategory(TableBase):
223 __tablename__ = 'item_categories'
224 id = Column(Integer, primary_key=True, nullable=False)
225 pocket_id = Column(Integer, ForeignKey('item_pockets.id'), nullable=False)
226 name = Column(Unicode(16), nullable=False)
227
228 class ItemFlag(TableBase):
229 __tablename__ = 'item_flags'
230 id = Column(Integer, primary_key=True, nullable=False)
231 identifier = Column(Unicode(24), nullable=False)
232 name = Column(Unicode(64), nullable=False)
233
234 class ItemFlagMap(TableBase):
235 __tablename__ = 'item_flag_map'
236 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False)
237 item_flag_id = Column(Integer, ForeignKey('item_flags.id'), primary_key=True, autoincrement=False, nullable=False)
238
239 class ItemFlavorText(TableBase):
240 __tablename__ = 'item_flavor_text'
241 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False)
242 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False)
243 flavor_text = Column(Unicode(255), nullable=False)
244
245 class ItemFlingEffect(TableBase):
246 __tablename__ = 'item_fling_effects'
247 id = Column(Integer, primary_key=True, nullable=False)
248 effect = Column(Unicode(255), nullable=False)
249
250 class ItemInternalID(TableBase):
251 __tablename__ = 'item_internal_ids'
252 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False)
253 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False)
254 internal_id = Column(Integer, nullable=False)
255
256 class ItemName(TableBase):
257 __tablename__ = 'item_names'
258 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, nullable=False, autoincrement=False)
259 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
260 name = Column(Unicode(16), nullable=False)
261
262 class ItemPocket(TableBase):
263 __tablename__ = 'item_pockets'
264 id = Column(Integer, primary_key=True, nullable=False)
265 identifier = Column(Unicode(16), nullable=False)
266 name = Column(Unicode(16), nullable=False)
267
268 class Language(TableBase):
269 __tablename__ = 'languages'
270 id = Column(Integer, primary_key=True, nullable=False)
271 iso639 = Column(Unicode(2), nullable=False)
272 iso3166 = Column(Unicode(2), nullable=False)
273 name = Column(Unicode(16), nullable=False)
274
275 class Location(TableBase):
276 __tablename__ = 'locations'
277 __singlename__ = 'location'
278 id = Column(Integer, primary_key=True, nullable=False)
279 region_id = Column(Integer, ForeignKey('regions.id'))
280 name = Column(Unicode(64), nullable=False)
281
282 class LocationArea(TableBase):
283 __tablename__ = 'location_areas'
284 id = Column(Integer, primary_key=True, nullable=False)
285 location_id = Column(Integer, ForeignKey('locations.id'), nullable=False)
286 internal_id = Column(Integer, nullable=False)
287 name = Column(Unicode(64), nullable=True)
288
289 class LocationAreaEncounterRate(TableBase):
290 __tablename__ = 'location_area_encounter_rates'
291 location_area_id = Column(Integer, ForeignKey('location_areas.id'), primary_key=True, nullable=False, autoincrement=False)
292 encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=True, nullable=False, autoincrement=False)
293 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, autoincrement=False)
294 rate = Column(Integer, nullable=True)
295
296 class LocationInternalID(TableBase):
297 __tablename__ = 'location_internal_ids'
298 location_id = Column(Integer, ForeignKey('locations.id'), nullable=False, primary_key=True)
299 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True)
300 internal_id = Column(Integer, nullable=False)
301
302 class Machine(TableBase):
303 __tablename__ = 'machines'
304 machine_number = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
305 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
306 item_id = Column(Integer, ForeignKey('items.id'), nullable=False)
307 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False)
308
309 @property
310 def is_hm(self):
311 return self.machine_number >= 100
312
313 class MoveBattleStyle(TableBase):
314 __tablename__ = 'move_battle_styles'
315 id = Column(Integer, primary_key=True, nullable=False)
316 name = Column(Unicode(8), nullable=False)
317
318 class MoveEffectCategory(TableBase):
319 __tablename__ = 'move_effect_categories'
320 id = Column(Integer, primary_key=True, nullable=False)
321 name = Column(Unicode(64), nullable=False)
322 can_affect_user = Column(Boolean, nullable=False)
323
324 class MoveEffectCategoryMap(TableBase):
325 __tablename__ = 'move_effect_category_map'
326 move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False)
327 move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False)
328 affects_user = Column(Boolean, primary_key=True, nullable=False)
329
330 class MoveDamageClass(TableBase):
331 __tablename__ = 'move_damage_classes'
332 id = Column(Integer, primary_key=True, nullable=False)
333 name = Column(Unicode(8), nullable=False)
334 description = Column(Unicode(64), nullable=False)
335
336 class MoveEffect(TableBase):
337 __tablename__ = 'move_effects'
338 id = Column(Integer, primary_key=True, nullable=False)
339 priority = Column(SmallInteger, nullable=False)
340 short_effect = Column(Unicode(256), nullable=False)
341 effect = Column(Unicode(5120), nullable=False)
342
343 class MoveFlag(TableBase):
344 __tablename__ = 'move_flags'
345 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
346 move_flag_type_id = Column(Integer, ForeignKey('move_flag_types.id'), primary_key=True, nullable=False, autoincrement=False)
347
348 class MoveFlagType(TableBase):
349 __tablename__ = 'move_flag_types'
350 id = Column(Integer, primary_key=True, nullable=False)
351 identifier = Column(Unicode(16), nullable=False)
352 name = Column(Unicode(32), nullable=False)
353 description = Column(markdown.MarkdownColumn(128), nullable=False)
354
355 class MoveFlavorText(TableBase):
356 __tablename__ = 'move_flavor_text'
357 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
358 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
359 flavor_text = Column(Unicode(255), nullable=False)
360
361 class MoveName(TableBase):
362 __tablename__ = 'move_names'
363 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
364 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
365 name = Column(Unicode(16), nullable=False)
366
367 class MoveTarget(TableBase):
368 __tablename__ = 'move_targets'
369 id = Column(Integer, primary_key=True, nullable=False)
370 name = Column(Unicode(32), nullable=False)
371 description = Column(Unicode(128), nullable=False)
372
373 class Move(TableBase):
374 __tablename__ = 'moves'
375 __singlename__ = 'move'
376 id = Column(Integer, primary_key=True, nullable=False)
377 name = Column(Unicode(12), nullable=False)
378 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
379 type_id = Column(Integer, ForeignKey('types.id'), nullable=False)
380 power = Column(SmallInteger)
381 pp = Column(SmallInteger, nullable=False)
382 accuracy = Column(SmallInteger)
383 target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False)
384 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False)
385 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False)
386 effect_chance = Column(Integer)
387 contest_type_id = Column(Integer, ForeignKey('contest_types.id'), nullable=True)
388 contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True)
389 super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=False)
390
391 class Nature(TableBase):
392 __tablename__ = 'natures'
393 __singlename__ = 'nature'
394 id = Column(Integer, primary_key=True, nullable=False)
395 name = Column(Unicode(8), nullable=False)
396 decreased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False)
397 increased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False)
398 hates_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False)
399 likes_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False)
400
401 @property
402 def is_neutral(self):
403 u"""Returns True iff this nature doesn't alter a Pokémon's stats,
404 bestow taste preferences, etc.
405 """
406 return self.increased_stat_id == self.decreased_stat_id
407
408 class NatureBattleStylePreference(TableBase):
409 __tablename__ = 'nature_battle_style_preferences'
410 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False)
411 move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False)
412 low_hp_preference = Column(Integer, nullable=False)
413 high_hp_preference = Column(Integer, nullable=False)
414
415 class NatureName(TableBase):
416 __tablename__ = 'nature_names'
417 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False, autoincrement=False)
418 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
419 name = Column(Unicode(8), nullable=False)
420
421 class NaturePokeathlonStat(TableBase):
422 __tablename__ = 'nature_pokeathlon_stats'
423 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False)
424 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False)
425 max_change = Column(Integer, nullable=False)
426
427 class PokeathlonStat(TableBase):
428 __tablename__ = 'pokeathlon_stats'
429 id = Column(Integer, primary_key=True, nullable=False)
430 name = Column(Unicode(8), nullable=False)
431
432 class Pokedex(TableBase):
433 __tablename__ = 'pokedexes'
434 id = Column(Integer, primary_key=True, nullable=False)
435 region_id = Column(Integer, ForeignKey('regions.id'), nullable=True)
436 name = Column(Unicode(16), nullable=False)
437 description = Column(Unicode(512))
438
439 class PokedexVersionGroup(TableBase):
440 __tablename__ = 'pokedex_version_groups'
441 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), primary_key=True, nullable=False, autoincrement=False)
442 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
443
444 class Pokemon(TableBase):
445 """The core to this whole mess.
446
447 Note that I use both 'forme' and 'form' in both code and the database. I
448 only use 'forme' when specifically referring to Pokémon that have multiple
449 distinct species as forms—i.e., different stats or movesets. 'Form' is a
450 more general term referring to any variation within a species, including
451 purely cosmetic forms like Unown.
452 """
453 __tablename__ = 'pokemon'
454 __singlename__ = 'pokemon'
455 id = Column(Integer, primary_key=True, nullable=False)
456 name = Column(Unicode(20), nullable=False)
457 forme_name = Column(Unicode(16))
458 forme_base_pokemon_id = Column(Integer, ForeignKey('pokemon.id'))
459 generation_id = Column(Integer, ForeignKey('generations.id'))
460 evolution_chain_id = Column(Integer, ForeignKey('evolution_chains.id'))
461 height = Column(Integer, nullable=False)
462 weight = Column(Integer, nullable=False)
463 species = Column(Unicode(16), nullable=False)
464 color_id = Column(Integer, ForeignKey('pokemon_colors.id'), nullable=False)
465 pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=False)
466 habitat_id = Column(Integer, ForeignKey('pokemon_habitats.id'), nullable=True)
467 gender_rate = Column(Integer, nullable=False)
468 capture_rate = Column(Integer, nullable=False)
469 base_experience = Column(Integer, nullable=False)
470 base_happiness = Column(Integer, nullable=False)
471 is_baby = Column(Boolean, nullable=False)
472 hatch_counter = Column(Integer, nullable=False)
473 has_gen4_fem_sprite = Column(Boolean, nullable=False)
474 has_gen4_fem_back_sprite = Column(Boolean, nullable=False)
475
476 ### Stuff to handle alternate Pokémon forms
477
478 @property
479 def national_id(self):
480 """Returns the National Pokédex number for this Pokémon. Use this
481 instead of the id directly; alternate formes may make the id incorrect.
482 """
483
484 if self.forme_base_pokemon_id:
485 return self.forme_base_pokemon_id
486 return self.id
487
488 @property
489 def full_name(self):
490 """Returns the name of this Pokémon, including its Forme, if any."""
491
492 if self.forme_name:
493 return "%s %s" % (self.forme_name.title(), self.name)
494 return self.name
495
496 @property
497 def normal_form(self):
498 """Returns the normal form for this Pokémon; i.e., this will return
499 regular Deoxys when called on any Deoxys form.
500 """
501
502 if self.forme_base_pokemon:
503 return self.forme_base_pokemon
504
505 return self
506
507 ### Not forms!
508
509 def stat(self, stat_name):
510 """Returns a PokemonStat record for the given stat name (or Stat row
511 object). Uses the normal has-many machinery, so all the stats are
512 effectively cached.
513 """
514 if isinstance(stat_name, Stat):
515 stat_name = stat_name.name
516
517 for pokemon_stat in self.stats:
518 if pokemon_stat.stat.name == stat_name:
519 return pokemon_stat
520
521 raise KeyError(u'No stat named %s' % stat_name)
522
523 @property
524 def better_damage_class(self):
525 u"""Returns the MoveDamageClass that this Pokémon is best suited for,
526 based on its attack stats.
527
528 If the attack stats are about equal (within 5), returns None. The
529 value None, not the damage class called 'None'.
530 """
531 phys = self.stat(u'Attack')
532 spec = self.stat(u'Special Attack')
533
534 diff = phys.base_stat - spec.base_stat
535
536 if diff > 5:
537 return phys.stat.damage_class
538 elif diff < -5:
539 return spec.stat.damage_class
540 else:
541 return None
542
543 class PokemonAbility(TableBase):
544 __tablename__ = 'pokemon_abilities'
545 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
546 ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False)
547 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
548
549 class PokemonColor(TableBase):
550 __tablename__ = 'pokemon_colors'
551 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
552 name = Column(Unicode(6), nullable=False)
553
554 class PokemonDexNumber(TableBase):
555 __tablename__ = 'pokemon_dex_numbers'
556 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
557 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), primary_key=True, nullable=False, autoincrement=False)
558 pokedex_number = Column(Integer, nullable=False)
559
560 class PokemonEggGroup(TableBase):
561 __tablename__ = 'pokemon_egg_groups'
562 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
563 egg_group_id = Column(Integer, ForeignKey('egg_groups.id'), primary_key=True, nullable=False, autoincrement=False)
564
565 class PokemonEvolution(TableBase):
566 __tablename__ = 'pokemon_evolution'
567 from_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False)
568 to_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
569 evolution_trigger_id = Column(Integer, ForeignKey('evolution_triggers.id'), nullable=False)
570 trigger_item_id = Column(Integer, ForeignKey('items.id'), nullable=True)
571 minimum_level = Column(Integer, nullable=True)
572 gender = Column(Enum('male', 'female', name='pokemon_evolution_gender'), nullable=True)
573 location_id = Column(Integer, ForeignKey('locations.id'), nullable=True)
574 held_item_id = Column(Integer, ForeignKey('items.id'), nullable=True)
575 time_of_day = Column(Enum('morning', 'day', 'night', name='pokemon_evolution_time_of_day'), nullable=True)
576 known_move_id = Column(Integer, ForeignKey('moves.id'), nullable=True)
577 minimum_happiness = Column(Integer, nullable=True)
578 minimum_beauty = Column(Integer, nullable=True)
579 relative_physical_stats = Column(Integer, nullable=True)
580 party_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True)
581
582 class PokemonFlavorText(TableBase):
583 __tablename__ = 'pokemon_flavor_text'
584 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
585 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False)
586 flavor_text = Column(Unicode(255), nullable=False)
587
588 class PokemonFormGroup(TableBase):
589 __tablename__ = 'pokemon_form_groups'
590 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
591 is_battle_only = Column(Boolean, nullable=False)
592 description = Column(markdown.MarkdownColumn(1024), nullable=False)
593
594 class PokemonFormSprite(TableBase):
595 __tablename__ = 'pokemon_form_sprites'
596 id = Column(Integer, primary_key=True, nullable=False)
597 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
598 introduced_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
599 name = Column(Unicode(16), nullable=True)
600 is_default = Column(Boolean, nullable=True)
601
602 class PokemonHabitat(TableBase):
603 __tablename__ = 'pokemon_habitats'
604 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
605 name = Column(Unicode(16), nullable=False)
606
607 class PokemonInternalID(TableBase):
608 __tablename__ = 'pokemon_internal_ids'
609 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False)
610 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False)
611 internal_id = Column(Integer, nullable=False)
612
613 class PokemonItem(TableBase):
614 __tablename__ = 'pokemon_items'
615 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
616 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False)
617 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, nullable=False, autoincrement=False)
618 rarity = Column(Integer, nullable=False)
619
620 class PokemonMove(TableBase):
621 __tablename__ = 'pokemon_moves'
622 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
623 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
624 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False, index=True)
625 pokemon_move_method_id = Column(Integer, ForeignKey('pokemon_move_methods.id'), primary_key=True, nullable=False, autoincrement=False)
626 level = Column(Integer, primary_key=True, nullable=True, autoincrement=False, index=True)
627 order = Column(Integer, nullable=True, index=True)
628
629 class PokemonMoveMethod(TableBase):
630 __tablename__ = 'pokemon_move_methods'
631 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
632 name = Column(Unicode(64), nullable=False)
633 description = Column(Unicode(255), nullable=False)
634
635 class PokemonName(TableBase):
636 __tablename__ = 'pokemon_names'
637 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
638 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
639 name = Column(Unicode(16), nullable=False)
640
641 class PokemonShape(TableBase):
642 __tablename__ = 'pokemon_shapes'
643 id = Column(Integer, primary_key=True, nullable=False)
644 name = Column(Unicode(24), nullable=False)
645 awesome_name = Column(Unicode(16), nullable=False)
646
647 class PokemonStat(TableBase):
648 __tablename__ = 'pokemon_stats'
649 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
650 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False)
651 base_stat = Column(Integer, nullable=False)
652 effort = Column(Integer, nullable=False)
653
654 class PokemonType(TableBase):
655 __tablename__ = 'pokemon_types'
656 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
657 type_id = Column(Integer, ForeignKey('types.id'), nullable=False)
658 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
659
660 class Region(TableBase):
661 """Major areas of the world: Kanto, Johto, etc."""
662 __tablename__ = 'regions'
663 id = Column(Integer, primary_key=True, nullable=False)
664 name = Column(Unicode(16), nullable=False)
665
666 class Stat(TableBase):
667 __tablename__ = 'stats'
668 id = Column(Integer, primary_key=True, nullable=False)
669 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True)
670 name = Column(Unicode(16), nullable=False)
671
672 class SuperContestCombo(TableBase):
673 __tablename__ = 'super_contest_combos'
674 first_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
675 second_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
676
677 class SuperContestEffect(TableBase):
678 __tablename__ = 'super_contest_effects'
679 id = Column(Integer, primary_key=True, nullable=False)
680 appeal = Column(SmallInteger, nullable=False)
681 flavor_text = Column(Unicode(64), nullable=False)
682
683 class TypeEfficacy(TableBase):
684 __tablename__ = 'type_efficacy'
685 damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False)
686 target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False)
687 damage_factor = Column(Integer, nullable=False)
688
689 class Type(TableBase):
690 __tablename__ = 'types'
691 __singlename__ = 'type'
692 id = Column(Integer, primary_key=True, nullable=False)
693 name = Column(Unicode(8), nullable=False)
694 abbreviation = Column(Unicode(3), nullable=False)
695 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
696 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False) ## ??? is none; everything else is physical or special
697
698 class TypeName(TableBase):
699 __tablename__ = 'type_names'
700 type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False)
701 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
702 name = Column(Unicode(16), nullable=False)
703
704 class VersionGroup(TableBase):
705 __tablename__ = 'version_groups'
706 id = Column(Integer, primary_key=True, nullable=False)
707 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
708
709 class VersionGroupRegion(TableBase):
710 __tablename__ = 'version_group_regions'
711 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False)
712 region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False)
713
714 class Version(TableBase):
715 __tablename__ = 'versions'
716 id = Column(Integer, primary_key=True, nullable=False)
717 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False)
718 name = Column(Unicode(32), nullable=False)
719
720
721 ### Relations down here, to avoid ordering problems
722 Ability.flavor_text = relation(AbilityFlavorText, order_by=AbilityFlavorText.version_group_id, backref='ability')
723 Ability.foreign_names = relation(AbilityName, backref='ability')
724 Ability.generation = relation(Generation, backref='abilities')
725
726 AbilityFlavorText.version_group = relation(VersionGroup)
727
728 AbilityName.language = relation(Language)
729
730 Berry.berry_firmness = relation(BerryFirmness, backref='berries')
731 Berry.firmness = association_proxy('berry_firmness', 'name')
732 Berry.flavors = relation(BerryFlavor, order_by=BerryFlavor.contest_type_id, backref='berry')
733 Berry.natural_gift_type = relation(Type)
734
735 BerryFlavor.contest_type = relation(ContestType)
736
737 ContestCombo.first = relation(Move, primaryjoin=ContestCombo.first_move_id==Move.id,
738 backref='contest_combo_first')
739 ContestCombo.second = relation(Move, primaryjoin=ContestCombo.second_move_id==Move.id,
740 backref='contest_combo_second')
741
742 Encounter.location_area = relation(LocationArea, backref='encounters')
743 Encounter.pokemon = relation(Pokemon, backref='encounters')
744 Encounter.version = relation(Version, backref='encounters')
745 Encounter.slot = relation(EncounterSlot, backref='encounters')
746
747 EncounterConditionValue.condition = relation(EncounterCondition, backref='values')
748
749 Encounter.condition_value_map = relation(EncounterConditionValueMap, backref='encounter')
750 Encounter.condition_values = association_proxy('condition_value_map', 'condition_value')
751 EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
752 backref='encounter_map')
753
754 EncounterSlot.terrain = relation(EncounterTerrain, backref='slots')
755
756 EncounterSlot.condition_map = relation(EncounterSlotCondition, backref='slot')
757 EncounterSlot.conditions = association_proxy('condition_map', 'condition')
758 EncounterSlotCondition.condition = relation(EncounterCondition,
759 backref='slot_map')
760
761 EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
762 EvolutionChain.baby_trigger_item = relation(Item, backref='evolution_chains')
763
764 Experience.growth_rate = relation(GrowthRate, backref='experience_table')
765
766 Generation.canonical_pokedex = relation(Pokedex, backref='canonical_for_generation')
767 Generation.versions = relation(Version, secondary=VersionGroup.__table__)
768 Generation.main_region = relation(Region)
769
770 GrowthRate.max_experience_obj = relation(Experience, primaryjoin=and_(Experience.growth_rate_id == GrowthRate.id, Experience.level == 100), uselist=False)
771 GrowthRate.max_experience = association_proxy('max_experience_obj', 'experience')
772
773 Item.berry = relation(Berry, uselist=False, backref='item')
774 Item.flags = relation(ItemFlag, secondary=ItemFlagMap.__table__)
775 Item.flavor_text = relation(ItemFlavorText, order_by=ItemFlavorText.version_group_id.asc(), backref='item')
776 Item.fling_effect = relation(ItemFlingEffect, backref='items')
777 Item.foreign_names = relation(ItemName, backref='item')
778 Item.machines = relation(Machine, order_by=Machine.version_group_id.asc())
779 Item.category = relation(ItemCategory)
780 Item.pocket = association_proxy('category', 'pocket')
781
782 ItemCategory.items = relation(Item, order_by=Item.name)
783 ItemCategory.pocket = relation(ItemPocket)
784
785 ItemFlavorText.version_group = relation(VersionGroup)
786
787 ItemInternalID.item = relation(Item, backref='internal_ids')
788 ItemInternalID.generation = relation(Generation)
789
790 ItemName.language = relation(Language)
791
792 ItemPocket.categories = relation(ItemCategory, order_by=ItemCategory.name)
793
794 Location.region = relation(Region, backref='locations')
795
796 LocationArea.location = relation(Location, backref='areas')
797
798 LocationInternalID.location = relation(Location, backref='internal_ids')
799 LocationInternalID.generation = relation(Generation)
800
801 Machine.item = relation(Item)
802 Machine.version_group = relation(VersionGroup)
803
804 Move.contest_effect = relation(ContestEffect, backref='moves')
805 Move.contest_combo_next = association_proxy('contest_combo_first', 'second')
806 Move.contest_combo_prev = association_proxy('contest_combo_second', 'first')
807 Move.contest_type = relation(ContestType, backref='moves')
808 Move.damage_class = relation(MoveDamageClass, backref='moves')
809 Move.flags = association_proxy('move_flags', 'flag')
810 Move.flavor_text = relation(MoveFlavorText, order_by=MoveFlavorText.version_group_id, backref='move')
811 Move.foreign_names = relation(MoveName, backref='move')
812 Move.generation = relation(Generation, backref='moves')
813 Move.machines = relation(Machine, backref='move')
814 Move.move_effect = relation(MoveEffect, backref='moves')
815 Move.move_flags = relation(MoveFlag, backref='move')
816 Move.super_contest_effect = relation(SuperContestEffect, backref='moves')
817 Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
818 Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
819 Move.target = relation(MoveTarget, backref='moves')
820 Move.type = relation(Type, backref='moves')
821
822 Move.effect = markdown.MoveEffectProperty('effect')
823 Move.priority = association_proxy('move_effect', 'priority')
824 Move.short_effect = markdown.MoveEffectProperty('short_effect')
825
826 MoveEffect.category_map = relation(MoveEffectCategoryMap)
827 MoveEffect.categories = association_proxy('category_map', 'category')
828 MoveEffectCategoryMap.category = relation(MoveEffectCategory)
829
830 MoveFlag.flag = relation(MoveFlagType)
831
832 MoveFlavorText.version_group = relation(VersionGroup)
833
834 MoveName.language = relation(Language)
835
836 Nature.foreign_names = relation(NatureName, backref='nature')
837 Nature.decreased_stat = relation(Stat, primaryjoin=Nature.decreased_stat_id==Stat.id,
838 backref='decreasing_natures')
839 Nature.increased_stat = relation(Stat, primaryjoin=Nature.increased_stat_id==Stat.id,
840 backref='increasing_natures')
841 Nature.hates_flavor = relation(ContestType, primaryjoin=Nature.hates_flavor_id==ContestType.id,
842 backref='hating_natures')
843 Nature.likes_flavor = relation(ContestType, primaryjoin=Nature.likes_flavor_id==ContestType.id,
844 backref='liking_natures')
845 Nature.battle_style_preferences = relation(NatureBattleStylePreference,
846 order_by=NatureBattleStylePreference.move_battle_style_id,
847 backref='nature')
848 Nature.pokeathlon_effects = relation(NaturePokeathlonStat, order_by=NaturePokeathlonStat.pokeathlon_stat_id)
849
850 NatureBattleStylePreference.battle_style = relation(MoveBattleStyle, backref='nature_preferences')
851
852 NatureName.language = relation(Language)
853
854 NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat, backref='nature_effects')
855
856 Pokedex.region = relation(Region, backref='pokedexes')
857 Pokedex.version_groups = relation(VersionGroup, secondary=PokedexVersionGroup.__table__, backref='pokedexes')
858
859 Pokemon.abilities = relation(Ability, secondary=PokemonAbility.__table__,
860 order_by=PokemonAbility.slot,
861 backref='pokemon')
862 Pokemon.formes = relation(Pokemon, primaryjoin=Pokemon.id==Pokemon.forme_base_pokemon_id,
863 backref=backref('forme_base_pokemon',
864 remote_side=[Pokemon.id]))
865 Pokemon.pokemon_color = relation(PokemonColor, backref='pokemon')
866 Pokemon.color = association_proxy('pokemon_color', 'name')
867 Pokemon.dex_numbers = relation(PokemonDexNumber, order_by=PokemonDexNumber.pokedex_id.asc(), backref='pokemon')
868 Pokemon.default_form_sprite = relation(PokemonFormSprite,
869 primaryjoin=and_(
870 Pokemon.id==PokemonFormSprite.pokemon_id,
871 PokemonFormSprite.is_default==True,
872 ),
873 uselist=False)
874 Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
875 order_by=PokemonEggGroup.egg_group_id,
876 backref='pokemon')
877 Pokemon.evolution_chain = relation(EvolutionChain, backref='pokemon')
878 Pokemon.child_pokemon = relation(Pokemon,
879 primaryjoin=Pokemon.id==PokemonEvolution.from_pokemon_id,
880 secondary=PokemonEvolution.__table__,
881 secondaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
882 backref=backref('parent_pokemon', uselist=False),
883 )
884 Pokemon.flavor_text = relation(PokemonFlavorText, order_by=PokemonFlavorText.version_id.asc(), backref='pokemon')
885 Pokemon.foreign_names = relation(PokemonName, backref='pokemon')
886 Pokemon.pokemon_habitat = relation(PokemonHabitat, backref='pokemon')
887 Pokemon.habitat = association_proxy('pokemon_habitat', 'name')
888 Pokemon.items = relation(PokemonItem, backref='pokemon')
889 Pokemon.generation = relation(Generation, backref='pokemon')
890 Pokemon.shape = relation(PokemonShape, backref='pokemon')
891 Pokemon.stats = relation(PokemonStat, backref='pokemon')
892 Pokemon.types = relation(Type, secondary=PokemonType.__table__, order_by=PokemonType.slot.asc())
893
894 PokemonDexNumber.pokedex = relation(Pokedex)
895
896 PokemonEvolution.from_pokemon = relation(Pokemon,
897 primaryjoin=PokemonEvolution.from_pokemon_id==Pokemon.id,
898 backref='child_evolutions',
899 )
900 PokemonEvolution.to_pokemon = relation(Pokemon,
901 primaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
902 backref=backref('parent_evolution', uselist=False),
903 )
904 PokemonEvolution.child_evolutions = relation(PokemonEvolution,
905 primaryjoin=PokemonEvolution.from_pokemon_id==PokemonEvolution.to_pokemon_id,
906 foreign_keys=[PokemonEvolution.to_pokemon_id],
907 backref=backref('parent_evolution',
908 remote_side=[PokemonEvolution.from_pokemon_id],
909 uselist=False,
910 ),
911 )
912 PokemonEvolution.trigger = relation(EvolutionTrigger, backref='evolutions')
913 PokemonEvolution.trigger_item = relation(Item,
914 primaryjoin=PokemonEvolution.trigger_item_id==Item.id,
915 backref='triggered_evolutions',
916 )
917 PokemonEvolution.held_item = relation(Item,
918 primaryjoin=PokemonEvolution.held_item_id==Item.id,
919 backref='required_for_evolutions',
920 )
921 PokemonEvolution.location = relation(Location, backref='triggered_evolutions')
922 PokemonEvolution.known_move = relation(Move, backref='triggered_evolutions')
923 PokemonEvolution.party_pokemon = relation(Pokemon,
924 primaryjoin=PokemonEvolution.party_pokemon_id==Pokemon.id,
925 backref='triggered_evolutions',
926 )
927
928 PokemonFlavorText.version = relation(Version)
929
930 PokemonItem.item = relation(Item, backref='pokemon')
931 PokemonItem.version = relation(Version)
932
933 PokemonFormGroup.pokemon = relation(Pokemon, backref=backref('form_group',
934 uselist=False))
935 PokemonFormSprite.pokemon = relation(Pokemon, backref='form_sprites')
936 PokemonFormSprite.introduced_in = relation(VersionGroup)
937
938 PokemonMove.pokemon = relation(Pokemon, backref='pokemon_moves')
939 PokemonMove.version_group = relation(VersionGroup)
940 PokemonMove.machine = relation(Machine, backref='pokemon_moves',
941 primaryjoin=and_(Machine.version_group_id==PokemonMove.version_group_id,
942 Machine.move_id==PokemonMove.move_id),
943 foreign_keys=[Machine.version_group_id, Machine.move_id],
944 uselist=False)
945 PokemonMove.move = relation(Move, backref='pokemon_moves')
946 PokemonMove.method = relation(PokemonMoveMethod)
947
948 PokemonName.language = relation(Language)
949
950 PokemonStat.stat = relation(Stat)
951
952 # This is technically a has-many; Generation.main_region_id -> Region.id
953 Region.generation = relation(Generation, uselist=False)
954 Region.version_group_regions = relation(VersionGroupRegion, backref='region',
955 order_by='VersionGroupRegion.version_group_id')
956 Region.version_groups = association_proxy('version_group_regions', 'version_group')
957
958 Stat.damage_class = relation(MoveDamageClass, backref='stats')
959
960 SuperContestCombo.first = relation(Move, primaryjoin=SuperContestCombo.first_move_id==Move.id,
961 backref='super_contest_combo_first')
962 SuperContestCombo.second = relation(Move, primaryjoin=SuperContestCombo.second_move_id==Move.id,
963 backref='super_contest_combo_second')
964
965 Type.damage_efficacies = relation(TypeEfficacy,
966 primaryjoin=Type.id
967 ==TypeEfficacy.damage_type_id,
968 backref='damage_type')
969 Type.target_efficacies = relation(TypeEfficacy,
970 primaryjoin=Type.id
971 ==TypeEfficacy.target_type_id,
972 backref='target_type')
973
974 Type.generation = relation(Generation, backref='types')
975 Type.damage_class = relation(MoveDamageClass, backref='types')
976 Type.foreign_names = relation(TypeName, backref='type')
977
978 TypeName.language = relation(Language)
979
980 Version.version_group = relation(VersionGroup, backref='versions')
981 Version.generation = association_proxy('version_group', 'generation')
982
983 VersionGroup.generation = relation(Generation, backref='version_groups')
984 VersionGroup.version_group_regions = relation(VersionGroupRegion, backref='version_group')
985 VersionGroup.regions = association_proxy('version_group_regions', 'region')