Store each Pokémon's initial hatch counter instead of a step count.
[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 = Column(Unicode(12))
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 Machine(TableBase):
297 __tablename__ = 'machines'
298 machine_number = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
299 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
300 item_id = Column(Integer, ForeignKey('items.id'), nullable=False)
301 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False)
302
303 @property
304 def is_hm(self):
305 return self.machine_number >= 100
306
307 class MoveBattleStyle(TableBase):
308 __tablename__ = 'move_battle_styles'
309 id = Column(Integer, primary_key=True, nullable=False)
310 name = Column(Unicode(8), nullable=False)
311
312 class MoveEffectCategory(TableBase):
313 __tablename__ = 'move_effect_categories'
314 id = Column(Integer, primary_key=True, nullable=False)
315 name = Column(Unicode(64), nullable=False)
316 can_affect_user = Column(Boolean, nullable=False)
317
318 class MoveEffectCategoryMap(TableBase):
319 __tablename__ = 'move_effect_category_map'
320 move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False)
321 move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False)
322 affects_user = Column(Boolean, primary_key=True, nullable=False)
323
324 class MoveDamageClass(TableBase):
325 __tablename__ = 'move_damage_classes'
326 id = Column(Integer, primary_key=True, nullable=False)
327 name = Column(Unicode(8), nullable=False)
328 description = Column(Unicode(64), nullable=False)
329
330 class MoveEffect(TableBase):
331 __tablename__ = 'move_effects'
332 id = Column(Integer, primary_key=True, nullable=False)
333 priority = Column(SmallInteger, nullable=False)
334 short_effect = Column(Unicode(256), nullable=False)
335 effect = Column(Unicode(5120), nullable=False)
336
337 class MoveFlag(TableBase):
338 __tablename__ = 'move_flags'
339 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
340 move_flag_type_id = Column(Integer, ForeignKey('move_flag_types.id'), primary_key=True, nullable=False, autoincrement=False)
341
342 class MoveFlagType(TableBase):
343 __tablename__ = 'move_flag_types'
344 id = Column(Integer, primary_key=True, nullable=False)
345 name = Column(Unicode(32), nullable=False)
346 description = Column(markdown.MarkdownColumn(128), nullable=False)
347
348 class MoveFlavorText(TableBase):
349 __tablename__ = 'move_flavor_text'
350 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
351 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
352 flavor_text = Column(Unicode(255), nullable=False)
353
354 class MoveName(TableBase):
355 __tablename__ = 'move_names'
356 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
357 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
358 name = Column(Unicode(16), nullable=False)
359
360 class MoveTarget(TableBase):
361 __tablename__ = 'move_targets'
362 id = Column(Integer, primary_key=True, nullable=False)
363 name = Column(Unicode(32), nullable=False)
364 description = Column(Unicode(128), nullable=False)
365
366 class Move(TableBase):
367 __tablename__ = 'moves'
368 __singlename__ = 'move'
369 id = Column(Integer, primary_key=True, nullable=False)
370 name = Column(Unicode(12), nullable=False)
371 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
372 type_id = Column(Integer, ForeignKey('types.id'), nullable=False)
373 power = Column(SmallInteger)
374 pp = Column(SmallInteger, nullable=False)
375 accuracy = Column(SmallInteger)
376 target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False)
377 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False)
378 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False)
379 effect_chance = Column(Integer)
380 contest_type_id = Column(Integer, ForeignKey('contest_types.id'), nullable=True)
381 contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True)
382 super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=False)
383
384 class Nature(TableBase):
385 __tablename__ = 'natures'
386 __singlename__ = 'nature'
387 id = Column(Integer, primary_key=True, nullable=False)
388 name = Column(Unicode(8), nullable=False)
389 decreased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False)
390 increased_stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False)
391 hates_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False)
392 likes_flavor_id = Column(Integer, ForeignKey('contest_types.id'), nullable=False)
393
394 class NatureBattleStylePreference(TableBase):
395 __tablename__ = 'nature_battle_style_preferences'
396 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False)
397 move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False)
398 low_hp_preference = Column(Integer, nullable=False)
399 high_hp_preference = Column(Integer, nullable=False)
400
401 class NatureName(TableBase):
402 __tablename__ = 'nature_names'
403 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False, autoincrement=False)
404 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
405 name = Column(Unicode(8), nullable=False)
406
407 class NaturePokeathlonStat(TableBase):
408 __tablename__ = 'nature_pokeathlon_stats'
409 nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False)
410 pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False)
411 max_change = Column(Integer, nullable=False)
412
413 class PokeathlonStat(TableBase):
414 __tablename__ = 'pokeathlon_stats'
415 id = Column(Integer, primary_key=True, nullable=False)
416 name = Column(Unicode(8), nullable=False)
417
418 class Pokedex(TableBase):
419 __tablename__ = 'pokedexes'
420 id = Column(Integer, primary_key=True, nullable=False)
421 region_id = Column(Integer, ForeignKey('regions.id'), nullable=True)
422 name = Column(Unicode(16), nullable=False)
423 description = Column(Unicode(512))
424
425 class PokedexVersionGroup(TableBase):
426 __tablename__ = 'pokedex_version_groups'
427 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), primary_key=True, nullable=False, autoincrement=False)
428 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
429
430 class Pokemon(TableBase):
431 """The core to this whole mess.
432
433 Note that I use both 'forme' and 'form' in both code and the database. I
434 only use 'forme' when specifically referring to Pokémon that have multiple
435 distinct species as forms—i.e., different stats or movesets. 'Form' is a
436 more general term referring to any variation within a species, including
437 purely cosmetic forms like Unown.
438 """
439 __tablename__ = 'pokemon'
440 __singlename__ = 'pokemon'
441 id = Column(Integer, primary_key=True, nullable=False)
442 name = Column(Unicode(20), nullable=False)
443 forme_name = Column(Unicode(16))
444 forme_base_pokemon_id = Column(Integer, ForeignKey('pokemon.id'))
445 generation_id = Column(Integer, ForeignKey('generations.id'))
446 evolution_chain_id = Column(Integer, ForeignKey('evolution_chains.id'))
447 height = Column(Integer, nullable=False)
448 weight = Column(Integer, nullable=False)
449 species = Column(Unicode(16), nullable=False)
450 color_id = Column(Integer, ForeignKey('pokemon_colors.id'), nullable=False)
451 pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=False)
452 habitat_id = Column(Integer, ForeignKey('pokemon_habitats.id'), nullable=True)
453 gender_rate = Column(Integer, nullable=False)
454 capture_rate = Column(Integer, nullable=False)
455 base_experience = Column(Integer, nullable=False)
456 base_happiness = Column(Integer, nullable=False)
457 is_baby = Column(Boolean, nullable=False)
458 hatch_counter = Column(Integer, nullable=False)
459 has_gen4_fem_sprite = Column(Boolean, nullable=False)
460 has_gen4_fem_back_sprite = Column(Boolean, nullable=False)
461
462 ### Stuff to handle alternate Pokémon forms
463
464 @property
465 def national_id(self):
466 """Returns the National Pokédex number for this Pokémon. Use this
467 instead of the id directly; alternate formes may make the id incorrect.
468 """
469
470 if self.forme_base_pokemon_id:
471 return self.forme_base_pokemon_id
472 return self.id
473
474 @property
475 def full_name(self):
476 """Returns the name of this Pokémon, including its Forme, if any."""
477
478 if self.forme_name:
479 return "%s %s" % (self.forme_name.title(), self.name)
480 return self.name
481
482 @property
483 def normal_form(self):
484 """Returns the normal form for this Pokémon; i.e., this will return
485 regular Deoxys when called on any Deoxys form.
486 """
487
488 if self.forme_base_pokemon:
489 return self.forme_base_pokemon
490
491 return self
492
493 ### Not forms!
494
495 def stat(self, stat_name):
496 """Returns a PokemonStat record for the given stat name (or Stat row
497 object). Uses the normal has-many machinery, so all the stats are
498 effectively cached.
499 """
500 if isinstance(stat_name, Stat):
501 stat_name = stat_name.name
502
503 for pokemon_stat in self.stats:
504 if pokemon_stat.stat.name == stat_name:
505 return pokemon_stat
506
507 raise KeyError(u'No stat named %s' % stat_name)
508
509 @property
510 def better_damage_class(self):
511 u"""Returns the MoveDamageClass that this Pokémon is best suited for,
512 based on its attack stats.
513
514 If the attack stats are about equal (within 5), returns None. The
515 value None, not the damage class called 'None'.
516 """
517 phys = self.stat(u'Attack')
518 spec = self.stat(u'Special Attack')
519
520 diff = phys.base_stat - spec.base_stat
521
522 if diff > 5:
523 return phys.stat.damage_class
524 elif diff < -5:
525 return spec.stat.damage_class
526 else:
527 return None
528
529 class PokemonAbility(TableBase):
530 __tablename__ = 'pokemon_abilities'
531 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
532 ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False)
533 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
534
535 class PokemonColor(TableBase):
536 __tablename__ = 'pokemon_colors'
537 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
538 name = Column(Unicode(6), nullable=False)
539
540 class PokemonDexNumber(TableBase):
541 __tablename__ = 'pokemon_dex_numbers'
542 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
543 pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), primary_key=True, nullable=False, autoincrement=False)
544 pokedex_number = Column(Integer, nullable=False)
545
546 class PokemonEggGroup(TableBase):
547 __tablename__ = 'pokemon_egg_groups'
548 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
549 egg_group_id = Column(Integer, ForeignKey('egg_groups.id'), primary_key=True, nullable=False, autoincrement=False)
550
551 class PokemonEvolution(TableBase):
552 __tablename__ = 'pokemon_evolution'
553 from_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False)
554 to_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
555 evolution_trigger_id = Column(Integer, ForeignKey('evolution_triggers.id'), nullable=False)
556 trigger_item_id = Column(Integer, ForeignKey('items.id'), nullable=True)
557 minimum_level = Column(Integer, nullable=True)
558 gender = Column(Enum('male', 'female', name='pokemon_evolution_gender'), nullable=True)
559 location_id = Column(Integer, ForeignKey('locations.id'), nullable=True)
560 held_item_id = Column(Integer, ForeignKey('items.id'), nullable=True)
561 time_of_day = Column(Enum('morning', 'day', 'night', name='pokemon_evolution_time_of_day'), nullable=True)
562 known_move_id = Column(Integer, ForeignKey('moves.id'), nullable=True)
563 minimum_happiness = Column(Integer, nullable=True)
564 minimum_beauty = Column(Integer, nullable=True)
565 relative_physical_stats = Column(Integer, nullable=True)
566 party_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True)
567
568 class PokemonFlavorText(TableBase):
569 __tablename__ = 'pokemon_flavor_text'
570 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
571 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False)
572 flavor_text = Column(Unicode(255), nullable=False)
573
574 class PokemonFormGroup(TableBase):
575 __tablename__ = 'pokemon_form_groups'
576 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
577 is_battle_only = Column(Boolean, nullable=False)
578 description = Column(markdown.MarkdownColumn(1024), nullable=False)
579
580 class PokemonFormSprite(TableBase):
581 __tablename__ = 'pokemon_form_sprites'
582 id = Column(Integer, primary_key=True, nullable=False)
583 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
584 introduced_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
585 name = Column(Unicode(16), nullable=True)
586 is_default = Column(Boolean, nullable=True)
587
588 class PokemonHabitat(TableBase):
589 __tablename__ = 'pokemon_habitats'
590 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
591 name = Column(Unicode(16), nullable=False)
592
593 class PokemonInternalID(TableBase):
594 __tablename__ = 'pokemon_internal_ids'
595 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False)
596 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False)
597 internal_id = Column(Integer, nullable=False)
598
599 class PokemonItem(TableBase):
600 __tablename__ = 'pokemon_items'
601 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
602 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False)
603 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, nullable=False, autoincrement=False)
604 rarity = Column(Integer, nullable=False)
605
606 class PokemonMove(TableBase):
607 __tablename__ = 'pokemon_moves'
608 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
609 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
610 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False, index=True)
611 pokemon_move_method_id = Column(Integer, ForeignKey('pokemon_move_methods.id'), primary_key=True, nullable=False, autoincrement=False)
612 level = Column(Integer, primary_key=True, nullable=True, autoincrement=False, index=True)
613 order = Column(Integer, nullable=True, index=True)
614
615 class PokemonMoveMethod(TableBase):
616 __tablename__ = 'pokemon_move_methods'
617 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
618 name = Column(Unicode(64), nullable=False)
619 description = Column(Unicode(255), nullable=False)
620
621 class PokemonName(TableBase):
622 __tablename__ = 'pokemon_names'
623 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
624 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
625 name = Column(Unicode(16), nullable=False)
626
627 class PokemonShape(TableBase):
628 __tablename__ = 'pokemon_shapes'
629 id = Column(Integer, primary_key=True, nullable=False)
630 name = Column(Unicode(24), nullable=False)
631 awesome_name = Column(Unicode(16), nullable=False)
632
633 class PokemonStat(TableBase):
634 __tablename__ = 'pokemon_stats'
635 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
636 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False)
637 base_stat = Column(Integer, nullable=False)
638 effort = Column(Integer, nullable=False)
639
640 class PokemonType(TableBase):
641 __tablename__ = 'pokemon_types'
642 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
643 type_id = Column(Integer, ForeignKey('types.id'), nullable=False)
644 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
645
646 class Region(TableBase):
647 """Major areas of the world: Kanto, Johto, etc."""
648 __tablename__ = 'regions'
649 id = Column(Integer, primary_key=True, nullable=False)
650 name = Column(Unicode(16), nullable=False)
651
652 class Stat(TableBase):
653 __tablename__ = 'stats'
654 id = Column(Integer, primary_key=True, nullable=False)
655 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True)
656 name = Column(Unicode(16), nullable=False)
657
658 class SuperContestCombo(TableBase):
659 __tablename__ = 'super_contest_combos'
660 first_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
661 second_move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
662
663 class SuperContestEffect(TableBase):
664 __tablename__ = 'super_contest_effects'
665 id = Column(Integer, primary_key=True, nullable=False)
666 appeal = Column(SmallInteger, nullable=False)
667 flavor_text = Column(Unicode(64), nullable=False)
668
669 class TypeEfficacy(TableBase):
670 __tablename__ = 'type_efficacy'
671 damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False)
672 target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False)
673 damage_factor = Column(Integer, nullable=False)
674
675 class Type(TableBase):
676 __tablename__ = 'types'
677 __singlename__ = 'type'
678 id = Column(Integer, primary_key=True, nullable=False)
679 name = Column(Unicode(8), nullable=False)
680 abbreviation = Column(Unicode(3), nullable=False)
681 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
682 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False) ## ??? is none; everything else is physical or special
683
684 class VersionGroup(TableBase):
685 __tablename__ = 'version_groups'
686 id = Column(Integer, primary_key=True, nullable=False)
687 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
688
689 class VersionGroupRegion(TableBase):
690 __tablename__ = 'version_group_regions'
691 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False)
692 region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False)
693
694 class Version(TableBase):
695 __tablename__ = 'versions'
696 id = Column(Integer, primary_key=True, nullable=False)
697 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False)
698 name = Column(Unicode(32), nullable=False)
699
700
701 ### Relations down here, to avoid ordering problems
702 Ability.flavor_text = relation(AbilityFlavorText, order_by=AbilityFlavorText.version_group_id, backref='ability')
703 Ability.foreign_names = relation(AbilityName, backref='ability')
704 Ability.generation = relation(Generation, backref='abilities')
705
706 AbilityFlavorText.version_group = relation(VersionGroup)
707
708 AbilityName.language = relation(Language)
709
710 Berry.berry_firmness = relation(BerryFirmness, backref='berries')
711 Berry.firmness = association_proxy('berry_firmness', 'name')
712 Berry.flavors = relation(BerryFlavor, order_by=BerryFlavor.contest_type_id, backref='berry')
713 Berry.natural_gift_type = relation(Type)
714
715 BerryFlavor.contest_type = relation(ContestType)
716
717 ContestCombo.first = relation(Move, primaryjoin=ContestCombo.first_move_id==Move.id,
718 backref='contest_combo_first')
719 ContestCombo.second = relation(Move, primaryjoin=ContestCombo.second_move_id==Move.id,
720 backref='contest_combo_second')
721
722 Encounter.location_area = relation(LocationArea, backref='encounters')
723 Encounter.pokemon = relation(Pokemon, backref='encounters')
724 Encounter.version = relation(Version, backref='encounters')
725 Encounter.slot = relation(EncounterSlot, backref='encounters')
726
727 EncounterConditionValue.condition = relation(EncounterCondition, backref='values')
728
729 Encounter.condition_value_map = relation(EncounterConditionValueMap, backref='encounter')
730 Encounter.condition_values = association_proxy('condition_value_map', 'condition_value')
731 EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
732 backref='encounter_map')
733
734 EncounterSlot.terrain = relation(EncounterTerrain, backref='slots')
735
736 EncounterSlot.condition_map = relation(EncounterSlotCondition, backref='slot')
737 EncounterSlot.conditions = association_proxy('condition_map', 'condition')
738 EncounterSlotCondition.condition = relation(EncounterCondition,
739 backref='slot_map')
740
741 EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
742
743 Experience.growth_rate = relation(GrowthRate, backref='experience_table')
744
745 Generation.canonical_pokedex = relation(Pokedex, backref='canonical_for_generation')
746 Generation.versions = relation(Version, secondary=VersionGroup.__table__)
747 Generation.main_region = relation(Region)
748
749 GrowthRate.max_experience_obj = relation(Experience, primaryjoin=and_(Experience.growth_rate_id == GrowthRate.id, Experience.level == 100), uselist=False)
750 GrowthRate.max_experience = association_proxy('max_experience_obj', 'experience')
751
752 Item.berry = relation(Berry, uselist=False, backref='item')
753 Item.flags = relation(ItemFlag, secondary=ItemFlagMap.__table__)
754 Item.flavor_text = relation(ItemFlavorText, order_by=ItemFlavorText.version_group_id.asc(), backref='item')
755 Item.fling_effect = relation(ItemFlingEffect, backref='items')
756 Item.foreign_names = relation(ItemName, backref='item')
757 Item.machines = relation(Machine, order_by=Machine.version_group_id.asc())
758 Item.category = relation(ItemCategory)
759 Item.pocket = association_proxy('category', 'pocket')
760
761 ItemCategory.items = relation(Item, order_by=Item.name)
762 ItemCategory.pocket = relation(ItemPocket)
763
764 ItemFlavorText.version_group = relation(VersionGroup)
765
766 ItemName.language = relation(Language)
767
768 ItemPocket.categories = relation(ItemCategory, order_by=ItemCategory.name)
769
770 Location.region = relation(Region, backref='locations')
771
772 LocationArea.location = relation(Location, backref='areas')
773
774 Machine.item = relation(Item)
775 Machine.version_group = relation(VersionGroup)
776
777 Move.contest_effect = relation(ContestEffect, backref='moves')
778 Move.contest_combo_next = association_proxy('contest_combo_first', 'second')
779 Move.contest_combo_prev = association_proxy('contest_combo_second', 'first')
780 Move.contest_type = relation(ContestType, backref='moves')
781 Move.damage_class = relation(MoveDamageClass, backref='moves')
782 Move.flags = association_proxy('move_flags', 'flag')
783 Move.flavor_text = relation(MoveFlavorText, order_by=MoveFlavorText.version_group_id, backref='move')
784 Move.foreign_names = relation(MoveName, backref='move')
785 Move.generation = relation(Generation, backref='moves')
786 Move.machines = relation(Machine, backref='move')
787 Move.move_effect = relation(MoveEffect, backref='moves')
788 Move.move_flags = relation(MoveFlag, backref='move')
789 Move.super_contest_effect = relation(SuperContestEffect, backref='moves')
790 Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
791 Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
792 Move.target = relation(MoveTarget, backref='moves')
793 Move.type = relation(Type, backref='moves')
794
795 Move.effect = markdown.MoveEffectProperty('effect')
796 Move.priority = association_proxy('move_effect', 'priority')
797 Move.short_effect = markdown.MoveEffectProperty('short_effect')
798
799 MoveEffect.category_map = relation(MoveEffectCategoryMap)
800 MoveEffect.categories = association_proxy('category_map', 'category')
801 MoveEffectCategoryMap.category = relation(MoveEffectCategory)
802
803 MoveFlag.flag = relation(MoveFlagType)
804
805 MoveFlavorText.version_group = relation(VersionGroup)
806
807 MoveName.language = relation(Language)
808
809 Nature.foreign_names = relation(NatureName, backref='nature')
810 Nature.decreased_stat = relation(Stat, primaryjoin=Nature.decreased_stat_id==Stat.id,
811 backref='decreasing_natures')
812 Nature.increased_stat = relation(Stat, primaryjoin=Nature.increased_stat_id==Stat.id,
813 backref='increasing_natures')
814 Nature.hates_flavor = relation(ContestType, primaryjoin=Nature.hates_flavor_id==ContestType.id,
815 backref='hating_natures')
816 Nature.likes_flavor = relation(ContestType, primaryjoin=Nature.likes_flavor_id==ContestType.id,
817 backref='liking_natures')
818 Nature.battle_style_preferences = relation(NatureBattleStylePreference,
819 order_by=NatureBattleStylePreference.move_battle_style_id,
820 backref='nature')
821 Nature.pokeathlon_effects = relation(NaturePokeathlonStat, order_by=NaturePokeathlonStat.pokeathlon_stat_id)
822
823 NatureBattleStylePreference.battle_style = relation(MoveBattleStyle, backref='nature_preferences')
824
825 NatureName.language = relation(Language)
826
827 NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat, backref='nature_effects')
828
829 Pokedex.region = relation(Region, backref='pokedexes')
830 Pokedex.version_groups = relation(VersionGroup, secondary=PokedexVersionGroup.__table__, backref='pokedexes')
831
832 Pokemon.abilities = relation(Ability, secondary=PokemonAbility.__table__,
833 order_by=PokemonAbility.slot,
834 backref='pokemon')
835 Pokemon.formes = relation(Pokemon, primaryjoin=Pokemon.id==Pokemon.forme_base_pokemon_id,
836 backref=backref('forme_base_pokemon',
837 remote_side=[Pokemon.id]))
838 Pokemon.pokemon_color = relation(PokemonColor, backref='pokemon')
839 Pokemon.color = association_proxy('pokemon_color', 'name')
840 Pokemon.dex_numbers = relation(PokemonDexNumber, order_by=PokemonDexNumber.pokedex_id.asc(), backref='pokemon')
841 Pokemon.default_form_sprite = relation(PokemonFormSprite,
842 primaryjoin=and_(
843 Pokemon.id==PokemonFormSprite.pokemon_id,
844 PokemonFormSprite.is_default==True,
845 ),
846 uselist=False)
847 Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
848 order_by=PokemonEggGroup.egg_group_id,
849 backref='pokemon')
850 Pokemon.evolution_chain = relation(EvolutionChain, backref='pokemon')
851 Pokemon.child_pokemon = relation(Pokemon,
852 primaryjoin=Pokemon.id==PokemonEvolution.from_pokemon_id,
853 secondary=PokemonEvolution.__table__,
854 secondaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
855 backref=backref('parent_pokemon', uselist=False),
856 )
857 Pokemon.flavor_text = relation(PokemonFlavorText, order_by=PokemonFlavorText.version_id.asc(), backref='pokemon')
858 Pokemon.foreign_names = relation(PokemonName, backref='pokemon')
859 Pokemon.pokemon_habitat = relation(PokemonHabitat, backref='pokemon')
860 Pokemon.habitat = association_proxy('pokemon_habitat', 'name')
861 Pokemon.items = relation(PokemonItem, backref='pokemon')
862 Pokemon.generation = relation(Generation, backref='pokemon')
863 Pokemon.shape = relation(PokemonShape, backref='pokemon')
864 Pokemon.stats = relation(PokemonStat, backref='pokemon')
865 Pokemon.types = relation(Type, secondary=PokemonType.__table__, order_by=PokemonType.slot.asc())
866
867 PokemonDexNumber.pokedex = relation(Pokedex)
868
869 PokemonEvolution.from_pokemon = relation(Pokemon,
870 primaryjoin=PokemonEvolution.from_pokemon_id==Pokemon.id,
871 backref='child_evolutions',
872 )
873 PokemonEvolution.to_pokemon = relation(Pokemon,
874 primaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
875 backref=backref('parent_evolution', uselist=False),
876 )
877 PokemonEvolution.child_evolutions = relation(PokemonEvolution,
878 primaryjoin=PokemonEvolution.from_pokemon_id==PokemonEvolution.to_pokemon_id,
879 foreign_keys=[PokemonEvolution.to_pokemon_id],
880 backref=backref('parent_evolution',
881 remote_side=[PokemonEvolution.from_pokemon_id],
882 uselist=False,
883 ),
884 )
885 PokemonEvolution.trigger = relation(EvolutionTrigger, backref='evolutions')
886 PokemonEvolution.trigger_item = relation(Item,
887 primaryjoin=PokemonEvolution.trigger_item_id==Item.id,
888 backref='triggered_evolutions',
889 )
890 PokemonEvolution.held_item = relation(Item,
891 primaryjoin=PokemonEvolution.held_item_id==Item.id,
892 backref='required_for_evolutions',
893 )
894 PokemonEvolution.location = relation(Location, backref='triggered_evolutions')
895 PokemonEvolution.known_move = relation(Move, backref='triggered_evolutions')
896 PokemonEvolution.party_pokemon = relation(Pokemon,
897 primaryjoin=PokemonEvolution.party_pokemon_id==Pokemon.id,
898 backref='triggered_evolutions',
899 )
900
901 PokemonFlavorText.version = relation(Version)
902
903 PokemonItem.item = relation(Item, backref='pokemon')
904 PokemonItem.version = relation(Version)
905
906 PokemonFormGroup.pokemon = relation(Pokemon, backref=backref('form_group',
907 uselist=False))
908 PokemonFormSprite.pokemon = relation(Pokemon, backref='form_sprites')
909 PokemonFormSprite.introduced_in = relation(VersionGroup)
910
911 PokemonMove.pokemon = relation(Pokemon, backref='pokemon_moves')
912 PokemonMove.version_group = relation(VersionGroup)
913 PokemonMove.machine = relation(Machine, backref='pokemon_moves',
914 primaryjoin=and_(Machine.version_group_id==PokemonMove.version_group_id,
915 Machine.move_id==PokemonMove.move_id),
916 foreign_keys=[Machine.version_group_id, Machine.move_id],
917 uselist=False)
918 PokemonMove.move = relation(Move, backref='pokemon_moves')
919 PokemonMove.method = relation(PokemonMoveMethod)
920
921 PokemonName.language = relation(Language)
922
923 PokemonStat.stat = relation(Stat)
924
925 # This is technically a has-many; Generation.main_region_id -> Region.id
926 Region.generation = relation(Generation, uselist=False)
927 Region.version_group_regions = relation(VersionGroupRegion, backref='region',
928 order_by='VersionGroupRegion.version_group_id')
929 Region.version_groups = association_proxy('version_group_regions', 'version_group')
930
931 Stat.damage_class = relation(MoveDamageClass, backref='stats')
932
933 SuperContestCombo.first = relation(Move, primaryjoin=SuperContestCombo.first_move_id==Move.id,
934 backref='super_contest_combo_first')
935 SuperContestCombo.second = relation(Move, primaryjoin=SuperContestCombo.second_move_id==Move.id,
936 backref='super_contest_combo_second')
937
938 Type.damage_efficacies = relation(TypeEfficacy,
939 primaryjoin=Type.id
940 ==TypeEfficacy.damage_type_id,
941 backref='damage_type')
942 Type.target_efficacies = relation(TypeEfficacy,
943 primaryjoin=Type.id
944 ==TypeEfficacy.target_type_id,
945 backref='target_type')
946
947 Type.generation = relation(Generation, backref='types')
948 Type.damage_class = relation(MoveDamageClass, backref='types')
949
950 Version.version_group = relation(VersionGroup, backref='versions')
951 Version.generation = association_proxy('version_group', 'generation')
952
953 VersionGroup.generation = relation(Generation, backref='version_groups')
954 VersionGroup.version_group_regions = relation(VersionGroupRegion, backref='version_group')
955 VersionGroup.regions = association_proxy('version_group_regions', 'region')