Merge remote-tracking branch 'origin/encounters-i18n'
authorEevee <git@veekun.com>
Wed, 6 Apr 2011 05:32:51 +0000 (22:32 -0700)
committerEevee <git@veekun.com>
Wed, 6 Apr 2011 05:32:51 +0000 (22:32 -0700)
Conflicts:
pokedex/db/__init__.py

1  2 
pokedex/db/__init__.py
pokedex/db/markdown.py
pokedex/db/tables.py

diff --combined pokedex/db/__init__.py
@@@ -1,7 -1,10 +1,10 @@@
 -from sqlalchemy import MetaData, Table, engine_from_config, orm
+ # encoding: utf-8
+ import re
 +from sqlalchemy import engine_from_config, orm
  
  from ..defaults import get_default_db_uri
 -from .tables import metadata
 +from .tables import Language, metadata
  from .multilang import MultilangSession, MultilangScopedSession
  
  
@@@ -21,7 -24,7 +24,7 @@@ def connect(uri=None, session_args={}, 
          uri = get_default_db_uri()
  
      ### Do some fixery for MySQL
-     if uri[0:5] == 'mysql':
+     if uri.startswith('mysql:'):
          # MySQL uses latin1 for connections by default even if the server is
          # otherwise oozing with utf8; charset fixes this
          if 'charset' not in uri:
  
      all_session_args = dict(autoflush=True, autocommit=False, bind=engine)
      all_session_args.update(session_args)
 -    sm = orm.sessionmaker(class_=MultilangSession, **all_session_args)
 +    sm = orm.sessionmaker(class_=MultilangSession, language_class=Language,
 +        **all_session_args)
      session = MultilangScopedSession(sm)
  
 +    # Default to English.  Warning, magic constant, blah blah.  Trying to fetch
 +    # English here would kinda break on new databases.  TODO still not an ideal
 +    # solution, I guess.
 +    session._default_language_id = 9
 +
      return session
+ def identifier_from_name(name):
+     """Make a string safe to use as an identifier.
+     Valid characters are lowercase alphanumerics and "-". This function may
+     raise ValueError if it can't come up with a suitable identifier.
+     This function is useful for scripts which add things with names.
+     """
+     if isinstance(name, str):
+         identifier = name.decode('utf-8')
+     else:
+         identifier = name
+     identifier = identifier.lower()
+     identifier = identifier.replace(u'+', u' plus ')
+     identifier = re.sub(u'[ _–]+', u'-', identifier)
+     identifier = re.sub(u"['./;’(),:]", u'', identifier)
+     identifier = identifier.replace(u'é', u'e')
+     identifier = identifier.replace(u'♀', u'-f')
+     identifier = identifier.replace(u'♂', u'-m')
+     if identifier in (u'???', u'????'):
+         identifier = u'unknown'
+     elif identifier == u'!':
+         identifier = u'exclamation'
+     elif identifier == u'?':
+         identifier = u'question'
+     if not identifier.replace(u"-", u"").isalnum():
+         raise ValueError(identifier)
+     return identifier
diff --combined pokedex/db/markdown.py
@@@ -31,11 -31,17 +31,17 @@@ class MarkdownString(object)
      def __unicode__(self):
          return self.source_text
  
+     def __str__(self):
+         return unicode(self.source_text).encode()
+     def __html__(self):
+         return self.as_html
      @property
      def as_html(self):
          """Returns the string as HTML4."""
  
-         if self._as_html:
+         if self._as_html is not None:
              return self._as_html
  
          md = markdown.Markdown(
@@@ -106,9 -112,6 +112,9 @@@ class MarkdownColumn(sqlalchemy.types.T
      impl = sqlalchemy.types.Unicode
  
      def process_bind_param(self, value, dialect):
 +        if value is None:
 +            return None
 +
          if not isinstance(value, basestring):
              # Can't assign, e.g., MarkdownString objects yet
              raise NotImplementedError
          return unicode(value)
  
      def process_result_value(self, value, dialect):
 +        if value is None:
 +            return None
 +
          return MarkdownString(value)
diff --combined pokedex/db/tables.py
@@@ -62,9 -62,6 +62,9 @@@ class TableSuperclass(object)
      def __str__(self):
          return unicode(self).encode('utf8')
  
 +    def __repr__(self):
 +        return unicode(self).encode('utf8')
 +
  mapped_classes = []
  class TableMetaclass(DeclarativeMeta):
      def __init__(cls, name, bases, attrs):
@@@ -84,7 -81,7 +84,7 @@@ class Language(TableBase)
      """
      __tablename__ = 'languages'
      __singlename__ = 'language'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      iso639 = Column(Unicode(2), nullable=False,
          info=dict(description="The two-letter code of the country where this language is spoken. Note that it is not unique.", format='identifier'))
@@@ -111,7 -108,7 +111,7 @@@ class Ability(TableBase)
      """
      __tablename__ = 'abilities'
      __singlename__ = 'ability'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="This ability's unique ID; matches the games' internal ID"))
      identifier = Column(Unicode(24), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -124,9 -121,9 +124,9 @@@ create_translation_table('ability_names
          info=dict(description="The name", format='plaintext', official=True, ripped=True)),
  )
  create_translation_table('ability_prose', Ability, 'prose',
 -    effect = Column(markdown.MarkdownColumn(5120), nullable=False,
 +    effect = Column(markdown.MarkdownColumn(5120), nullable=True,
          info=dict(description="A detailed description of this ability's effect", format='markdown')),
 -    short_effect = Column(markdown.MarkdownColumn(255), nullable=False,
 +    short_effect = Column(markdown.MarkdownColumn(255), nullable=True,
          info=dict(description="A short summary of this ability's effect", format='markdown')),
  )
  
@@@ -134,7 -131,7 +134,7 @@@ class AbilityChangelog(TableBase)
      """History of changes to abilities across main game versions."""
      __tablename__ = 'ability_changelog'
      __singlename__ = 'ability_changelog'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="This change's unique ID"))
      ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False,
          info=dict(description="The ID of the ability that changed"))
@@@ -154,7 -151,7 +154,7 @@@ class AbilityFlavorText(TableBase)
          info=dict(description="The ID of the ability"))
      version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
          info=dict(description="The ID of the version group this flavor text is taken from"))
-     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
+     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
          info=dict(description="The language"))
      flavor_text = Column(Unicode(64), nullable=False,
          info=dict(description="The actual flavor text", official=True, format='gametext'))
@@@ -165,7 -162,7 +165,7 @@@ class Berry(TableBase)
      For data common to all items, such as the name, see the corresponding item entry.
      """
      __tablename__ = 'berries'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="This Berry's in-game number"))
      item_id = Column(Integer, ForeignKey('items.id'), nullable=False,
          info=dict(description="The ID of the item that represents this Berry"))
@@@ -191,7 -188,7 +191,7 @@@ class BerryFirmness(TableBase)
      """
      __tablename__ = 'berry_firmness'
      __singlename__ = 'berry_firmness'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A unique ID for this firmness"))
      identifier = Column(Unicode(10), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -227,7 -224,7 +227,7 @@@ class ContestEffect(TableBase)
      """
      __tablename__ = 'contest_effects'
      __singlename__ = 'contest_effect'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A unique ID for this effect"))
      appeal = Column(SmallInteger, nullable=False,
          info=dict(description="The base number of hearts the user of this move gets"))
          info=dict(description="The base number of hearts the user's opponent loses"))
  
  create_translation_table('contest_effect_prose', ContestEffect, 'prose',
 -    flavor_text = Column(Unicode(64), nullable=False,
 +    flavor_text = Column(Unicode(64), nullable=True,
          info=dict(description="The in-game description of this effect", official=True, format='gametext')),
 -    effect = Column(Unicode(255), nullable=False,
 +    effect = Column(Unicode(255), nullable=True,
          info=dict(description="A detailed description of the effect", format='plaintext')),
  )
  
@@@ -246,18 -243,18 +246,18 @@@ class ContestType(TableBase)
      """
      __tablename__ = 'contest_types'
      __singlename__ = 'contest_type'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A unique ID for this Contest type"))
      identifier = Column(Unicode(6), nullable=False,
          info=dict(description="An identifier", format='identifier'))
  
  create_translation_table('contest_type_names', ContestType, 'names',
      relation_lazy='joined',
 -    name = Column(Unicode(6), nullable=False, index=True,
 +    name = Column(Unicode(6), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=True)),
 -    flavor = Column(Unicode(6), nullable=False,
 +    flavor = Column(Unicode(6), nullable=True,
          info=dict(description="The name of the corresponding Berry flavor", official=True, format='plaintext')),
 -    color = Column(Unicode(6), nullable=False,
 +    color = Column(Unicode(6), nullable=True,
          info=dict(description=u"The name of the corresponding Pokéblock color", official=True, format='plaintext')),
  )
  
@@@ -268,7 -265,7 +268,7 @@@ class EggGroup(TableBase)
      """
      __tablename__ = 'egg_groups'
      __singlename__ = 'egg_group'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A unique ID for this group"))
      identifier = Column(Unicode(16), nullable=False,
          info=dict(description=u"An identifier.", format='identifier'))
@@@ -288,10 -285,10 +288,10 @@@ class Encounter(TableBase)
      "slot" they are in and the state of the game world.
  
      What the player is doing to get an encounter, such as surfing or walking
-     through tall grass, is called terrain.  Each terrain has its own set of
+     through tall grass, is called a method.  Each method has its own set of
      encounter slots.
  
-     Within a terrain, slots are defined primarily by rarity.  Each slot can
+     Within a method, slots are defined primarily by rarity.  Each slot can
      also be affected by world conditions; for example, the 20% slot for walking
      in tall grass is affected by whether a swarm is in effect in that area.
      "Is there a swarm?" is a condition; "there is a swarm" and "there is not a
      """
  
      __tablename__ = 'encounters'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A unique ID for this encounter"))
      version_id = Column(Integer, ForeignKey('versions.id'), nullable=False, autoincrement=False,
          info=dict(description="The ID of the version this applies to"))
      location_area_id = Column(Integer, ForeignKey('location_areas.id'), nullable=False, autoincrement=False,
          info=dict(description="The ID of the location of this encounter"))
      encounter_slot_id = Column(Integer, ForeignKey('encounter_slots.id'), nullable=False, autoincrement=False,
-         info=dict(description="The ID of the encounter slot, which determines terrain and rarity"))
+         info=dict(description="The ID of the encounter slot, which determines method and rarity"))
      pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
          info=dict(description=u"The ID of the encountered Pokémon"))
      min_level = Column(Integer, nullable=False, autoincrement=False,
@@@ -325,7 -322,7 +325,7 @@@ class EncounterCondition(TableBase)
  
      __tablename__ = 'encounter_conditions'
      __singlename__ = 'encounter_condition'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A unique ID for this condition"))
      identifier = Column(Unicode(64), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -341,7 -338,7 +341,7 @@@ class EncounterConditionValue(TableBase
  
      __tablename__ = 'encounter_condition_values'
      __singlename__ = 'encounter_condition_value'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      encounter_condition_id = Column(Integer, ForeignKey('encounter_conditions.id'), primary_key=False, nullable=False, autoincrement=False,
          info=dict(description="The ID of the encounter condition this is a value of"))
@@@ -364,46 -361,46 +364,46 @@@ class EncounterConditionValueMap(TableB
      encounter_condition_value_id = Column(Integer, ForeignKey('encounter_condition_values.id'), primary_key=True, nullable=False, autoincrement=False,
          info=dict(description="The ID of the encounter condition value"))
  
+ class EncounterMethod(TableBase):
+     u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
+     """
+     __tablename__ = 'encounter_methods'
+     __singlename__ = 'encounter_method'
+     id = Column(Integer, primary_key=True, nullable=False,
+         info=dict(description="A unique ID for the method"))
+     identifier = Column(Unicode(16), nullable=False, unique=True,
+         info=dict(description="An identifier", format='identifier'))
+ create_translation_table('encounter_method_prose', EncounterMethod, 'prose',
+     name = Column(Unicode(64), nullable=False, index=True,
+         info=dict(description="The name", format='plaintext', official=False)),
+ )
  class EncounterSlot(TableBase):
-     u"""An abstract "slot" within a terrain, associated with both some set of conditions and a rarity.
+     u"""An abstract "slot" within a method, associated with both some set of conditions and a rarity.
  
      Note that there are two encounters per slot, so the rarities will only add
      up to 50.
      """
  
      __tablename__ = 'encounter_slots'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A unique ID for this slot"))
      version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, autoincrement=False,
          info=dict(description="The ID of the version group this slot is in"))
-     encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=False, nullable=False, autoincrement=False,
-         info=dict(description="The ID of the terrain"))
+     encounter_method_id = Column(Integer, ForeignKey('encounter_methods.id'), primary_key=False, nullable=False, autoincrement=False,
+         info=dict(description="The ID of the method"))
      slot = Column(Integer, nullable=True,
-         info=dict(description="This slot's order for the location and terrain"))
-     rarity = Column(Integer, nullable=False,
+         info=dict(description="This slot's order for the location and method"))
+     rarity = Column(Integer, nullable=True,
          info=dict(description="The chance of the encounter as a percentage"))
  
- class EncounterTerrain(TableBase):
-     u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
-     """
-     __tablename__ = 'encounter_terrain'
-     __singlename__ = __tablename__
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
-         info=dict(description="A unique ID for the terrain"))
-     identifier = Column(Unicode(64), nullable=False,
-         info=dict(description="An identifier", format='identifier'))
- create_translation_table('encounter_terrain_prose', EncounterTerrain, 'prose',
-     name = Column(Unicode(64), nullable=False, index=True,
-         info=dict(description="The name", format='plaintext', official=False)),
- )
  class EvolutionChain(TableBase):
      u"""A family of Pokémon that are linked by evolution
      """
      __tablename__ = 'evolution_chains'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), nullable=False,
          info=dict(description="ID of the growth rate for this family"))
@@@ -415,7 -412,7 +415,7 @@@ class EvolutionTrigger(TableBase)
      """
      __tablename__ = 'evolution_triggers'
      __singlename__ = 'evolution_trigger'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(16), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -429,7 -426,7 +429,7 @@@ class Experience(TableBase)
      u"""EXP needed for a certain level with a certain growth rate
      """
      __tablename__ = 'experience'
-     growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), primary_key=True, nullable=False, autoincrement=False,
+     growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), primary_key=True, nullable=False,
          info=dict(description="ID of the growth rate"))
      level = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
          info=dict(description="The level"))
@@@ -441,7 -438,7 +441,7 @@@ class Generation(TableBase)
      """
      __tablename__ = 'generations'
      __singlename__ = 'generation'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      main_region_id = Column(Integer, ForeignKey('regions.id'), nullable=False,
          info=dict(description="ID of the region this generation's main games take place in"))
@@@ -461,7 -458,7 +461,7 @@@ class GrowthRate(TableBase)
      """
      __tablename__ = 'growth_rates'
      __singlename__ = 'growth_rate'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(20), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -478,7 -475,7 +478,7 @@@ class Item(TableBase)
      """
      __tablename__ = 'items'
      __singlename__ = 'item'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(20), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -503,9 -500,9 +503,9 @@@ create_translation_table('item_names', 
          info=dict(description="The name", format='plaintext', official=True, ripped=True)),
  )
  create_translation_table('item_prose', Item, 'prose',
 -    short_effect = Column(markdown.MarkdownColumn(256), nullable=False,
 -        info=dict(description="A short summary of the effect", format='plaintext')),
 -    effect = Column(markdown.MarkdownColumn(5120), nullable=False,
 +    short_effect = Column(markdown.MarkdownColumn(256), nullable=True,
 +        info=dict(description="A short summary of the effect", format='markdown')),
 +    effect = Column(markdown.MarkdownColumn(5120), nullable=True,
          info=dict(description=u"Detailed description of the item's effect.", format='markdown')),
  )
  create_translation_table('item_flavor_summaries', Item, 'flavor_summaries',
@@@ -519,7 -516,7 +519,7 @@@ class ItemCategory(TableBase)
      # XXX: This is fanon, right?
      __tablename__ = 'item_categories'
      __singlename__ = 'item_category'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      pocket_id = Column(Integer, ForeignKey('item_pockets.id'), nullable=False,
          info=dict(description="ID of the pocket these items go to"))
@@@ -537,15 -534,15 +537,15 @@@ class ItemFlag(TableBase)
      """
      __tablename__ = 'item_flags'
      __singlename__ = 'item_flag'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(24), nullable=False,
          info=dict(description="Identifier of the flag", format='identifier'))
  
  create_translation_table('item_flag_prose', ItemFlag, 'prose',
 -    name = Column(Unicode(24), nullable=False, index=True,
 +    name = Column(Unicode(24), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=False)),
 -    description = Column(Unicode(64), nullable=False,
 +    description = Column(Unicode(64), nullable=True,
          info=dict(description="Short description of the flag", format='plaintext')),
  )
  
@@@ -568,7 -565,7 +568,7 @@@ class ItemFlavorText(TableBase)
          info=dict(description="The ID of the item"))
      version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False,
          info=dict(description="ID of the version group that sports this text"))
-     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
+     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
          info=dict(description="The language"))
      flavor_text = Column(Unicode(255), nullable=False,
          info=dict(description="The flavor text itself", official=True, format='gametext'))
@@@ -578,7 -575,7 +578,7 @@@ class ItemFlingEffect(TableBase)
      """
      __tablename__ = 'item_fling_effects'
      __singlename__ = 'item_fling_effect'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
  
  create_translation_table('item_fling_effect_prose', ItemFlingEffect, 'prose',
@@@ -602,7 -599,7 +602,7 @@@ class ItemPocket(TableBase)
      """
      __tablename__ = 'item_pockets'
      __singlename__ = 'item_pocket'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(16), nullable=False,
          info=dict(description="An identifier of this pocket", format='identifier'))
@@@ -618,7 -615,7 +618,7 @@@ class Location(TableBase)
      """
      __tablename__ = 'locations'
      __singlename__ = 'location'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      region_id = Column(Integer, ForeignKey('regions.id'),
          info=dict(description="ID of the region this location is in"))
@@@ -636,7 -633,7 +636,7 @@@ class LocationArea(TableBase)
      """
      __tablename__ = 'location_areas'
      __singlename__ = 'location_area'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      location_id = Column(Integer, ForeignKey('locations.id'), nullable=False,
          info=dict(description="ID of the location this area is part of"))
@@@ -656,8 -653,8 +656,8 @@@ class LocationAreaEncounterRate(TableBa
      __tablename__ = 'location_area_encounter_rates'
      location_area_id = Column(Integer, ForeignKey('location_areas.id'), primary_key=True, nullable=False, autoincrement=False,
          info=dict(description="ID of the area"))
-     encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=True, nullable=False, autoincrement=False,
-         info=dict(description="ID of the terrain"))
+     encounter_method_id = Column(Integer, ForeignKey('encounter_methods.id'), primary_key=True, nullable=False, autoincrement=False,
+         info=dict(description="ID of the method"))
      version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, autoincrement=False,
          info=dict(description="ID of the version"))
      rate = Column(Integer, nullable=True,
@@@ -667,11 -664,11 +667,11 @@@ class LocationGameIndex(TableBase)
      u"""IDs the games use internally for locations
      """
      __tablename__ = 'location_game_indices'
-     location_id = Column(Integer, ForeignKey('locations.id'), nullable=False, primary_key=True, autoincrement=False,
+     location_id = Column(Integer, ForeignKey('locations.id'), nullable=False, primary_key=True,
          info=dict(description="Database ID of the locaion"))
-     generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True, autoincrement=False,
+     generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True,
          info=dict(description="ID of the generation this entry to"))
-     game_index = Column(Integer, nullable=False,
+     game_index = Column(Integer, nullable=False, primary_key=True, autoincrement=False,
          info=dict(description="Internal game ID of the location"))
  
  class Machine(TableBase):
@@@ -698,7 -695,7 +698,7 @@@ class Move(TableBase)
      """
      __tablename__ = 'moves'
      __singlename__ = 'move'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(24), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -743,7 -740,7 +743,7 @@@ class MoveBattleStyle(TableBase)
      u"""A battle style of a move"""  # XXX: Explain better
      __tablename__ = 'move_battle_styles'
      __singlename__ = 'move_battle_style'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(8), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -758,9 -755,9 +758,9 @@@ class MoveChangelog(TableBase)
      """History of changes to moves across main game versions."""
      __tablename__ = 'move_changelog'
      __singlename__ = 'move_changelog'
-     move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
+     move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
          info=dict(description="ID of the move that changed"))
-     changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
+     changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
          info=dict(description="ID of the version group in which the move changed"))
      type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
          info=dict(description="Prior type of the move, or NULL if unchanged"))
@@@ -780,16 -777,16 +780,16 @@@ class MoveDamageClass(TableBase)
      """
      __tablename__ = 'move_damage_classes'
      __singlename__ = 'move_damage_class'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(16), nullable=False,
          info=dict(description="An identifier", format='identifier'))
  
  create_translation_table('move_damage_class_prose', MoveDamageClass, 'prose',
      relation_lazy='joined',
 -    name = Column(Unicode(16), nullable=False, index=True,
 +    name = Column(Unicode(16), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=False)),
 -    description = Column(Unicode(64), nullable=False,
 +    description = Column(Unicode(64), nullable=True,
          info=dict(description="A description of the class", format='plaintext')),
  )
  
@@@ -798,13 -795,13 +798,13 @@@ class MoveEffect(TableBase)
      """
      __tablename__ = 'move_effects'
      __singlename__ = 'move_effect'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
  
  create_translation_table('move_effect_prose', MoveEffect, 'prose',
 -    short_effect = Column(Unicode(256), nullable=False,
 +    short_effect = Column(Unicode(256), nullable=True,
          info=dict(description="A short summary of the effect", format='plaintext')),
 -    effect = Column(Unicode(5120), nullable=False,
 +    effect = Column(Unicode(5120), nullable=True,
          info=dict(description="A detailed description of the effect", format='plaintext')),
  )
  
@@@ -813,7 -810,7 +813,7 @@@ class MoveEffectCategory(TableBase)
      """
      __tablename__ = 'move_effect_categories'
      __singlename__ = 'move_effect_category'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(64), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -829,18 -826,18 +829,18 @@@ class MoveEffectCategoryMap(TableBase)
      u"""Maps a move effect category to a move effect
      """
      __tablename__ = 'move_effect_category_map'
-     move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False, autoincrement=False,
+     move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False,
          info=dict(description="ID of the move effect"))
-     move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False, autoincrement=False,
+     move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False,
          info=dict(description="ID of the category"))
-     affects_user = Column(Boolean, primary_key=True, nullable=False, autoincrement=False,
+     affects_user = Column(Boolean, primary_key=True, nullable=False,
          info=dict(description="Set if the user is affected"))
  
  class MoveEffectChangelog(TableBase):
      """History of changes to move effects across main game versions."""
      __tablename__ = 'move_effect_changelog'
      __singlename__ = 'move_effect_changelog'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
          info=dict(description="The ID of the effect that changed"))
@@@ -873,16 -870,16 +873,16 @@@ class MoveFlagType(TableBase)
      """
      __tablename__ = 'move_flag_types'
      __singlename__ = 'move_flag_type'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(32), nullable=False,
          info=dict(description="A short identifier for the flag", format='identifier'))
  
  create_translation_table('move_flag_type_prose', MoveFlagType, 'prose',
      relation_lazy='joined',
 -    name = Column(Unicode(32), nullable=False, index=True,
 +    name = Column(Unicode(32), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=False)),
 -    description = Column(markdown.MarkdownColumn(128), nullable=False,
 +    description = Column(markdown.MarkdownColumn(128), nullable=True,
          info=dict(description="A short description of the flag", format='markdown')),
  )
  
@@@ -895,7 -892,7 +895,7 @@@ class MoveFlavorText(TableBase)
          info=dict(description="ID of the move"))
      version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
          info=dict(description="ID of the version group this text appears in"))
-     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
+     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
          info=dict(description="The language"))
      flavor_text = Column(Unicode(255), nullable=False,
          info=dict(description="The flavor text", official=True, format='gametext'))
@@@ -951,7 -948,7 +951,7 @@@ class MoveMetaCategory(TableBase)
      u"""Very general categories that loosely group move effects."""
      __tablename__ = 'move_meta_categories'
      __singlename__ = 'move_meta_category'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
  
  create_translation_table('move_meta_category_prose', MoveMetaCategory, 'prose',
@@@ -975,16 -972,16 +975,16 @@@ class MoveTarget(TableBase)
      """
      __tablename__ = 'move_targets'
      __singlename__ = 'move_target'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(32), nullable=False,
          info=dict(description="An identifier", format='identifier'))
  
  create_translation_table('move_target_prose', MoveTarget, 'prose',
      relation_lazy='joined',
 -    name = Column(Unicode(32), nullable=False, index=True,
 +    name = Column(Unicode(32), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=False)),
 -    description = Column(Unicode(128), nullable=False,
 +    description = Column(Unicode(128), nullable=True,
          info=dict(description="A description", format='plaintext')),
  )
  
@@@ -993,7 -990,7 +993,7 @@@ class Nature(TableBase)
      """
      __tablename__ = 'natures'
      __singlename__ = 'nature'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(8), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -1026,9 -1023,9 +1026,9 @@@ class NatureBattleStylePreference(Table
      a particular battl style in Battle Palace or Battle Tent
      """
      __tablename__ = 'nature_battle_style_preferences'
-     nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False, autoincrement=False,
+     nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
          info=dict(description=u"ID of the Pokémon's nature"))
-     move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False, autoincrement=False,
+     move_battle_style_id = Column(Integer, ForeignKey('move_battle_styles.id'), primary_key=True, nullable=False,
          info=dict(description="ID of the battle style"))
      low_hp_preference = Column(Integer, nullable=False,
          info=dict(description=u"Chance of using the move, in percent, if HP is under ½"))
@@@ -1039,9 -1036,9 +1039,9 @@@ class NaturePokeathlonStat(TableBase)
      u"""Specifies how a Nature affects a Pokéathlon stat
      """
      __tablename__ = 'nature_pokeathlon_stats'
-     nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False, autoincrement=False,
+     nature_id = Column(Integer, ForeignKey('natures.id'), primary_key=True, nullable=False,
          info=dict(description="ID of the nature"))
-     pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False, autoincrement=False,
+     pokeathlon_stat_id = Column(Integer, ForeignKey('pokeathlon_stats.id'), primary_key=True, nullable=False,
          info=dict(description="ID of the stat"))
      max_change = Column(Integer, nullable=False,
          info=dict(description="Maximum change"))
@@@ -1051,7 -1048,7 +1051,7 @@@ class PokeathlonStat(TableBase)
      """
      __tablename__ = 'pokeathlon_stats'
      __singlename__ = 'pokeathlon_stat'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      identifier = Column(Unicode(8), nullable=False,
          info=dict(description="An identifier", format='identifier'))
@@@ -1066,7 -1063,7 +1066,7 @@@ class Pokedex(TableBase)
      """
      __tablename__ = 'pokedexes'
      __singlename__ = 'pokedex'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description="A numeric ID"))
      region_id = Column(Integer, ForeignKey('regions.id'), nullable=True,
          info=dict(description=u"ID of the region this Pokédex is used in, or None if it's global"))
  
  create_translation_table('pokedex_prose', Pokedex, 'prose',
      relation_lazy='joined',
 -    name = Column(Unicode(16), nullable=False, index=True,
 +    name = Column(Unicode(16), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=False)),
 -    description = Column(Unicode(512), nullable=False,
 +    description = Column(Unicode(512), nullable=True,
          info=dict(description=u"A longer description of the Pokédex", format='plaintext')),
  )
  
@@@ -1086,7 -1083,7 +1086,7 @@@ class Pokemon(TableBase)
      """
      __tablename__ = 'pokemon'
      __singlename__ = 'pokemon'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"A numeric ID"))
      identifier = Column(Unicode(20), nullable=False,
          info=dict(description=u"An identifier", format='identifier'))
          u"""Returns the Pokémon's name, including its form if applicable."""
  
          if self.form_name:
-             return u'{0} {1}'.format(self.form_name, self.name)
+             return u'%s %s' % (self.form_name, self.name)
          else:
              return self.name
  
  
  create_translation_table('pokemon_names', Pokemon, 'names',
      relation_lazy='joined',
 -    name = Column(Unicode(20), nullable=False, index=True,
 +    name = Column(Unicode(20), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=True, ripped=True)),
 -    species = Column(Unicode(16), nullable=False,
 +    species = Column(Unicode(16), nullable=True,
          info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
          official=True, format='plaintext')),
  )
@@@ -1315,7 -1312,7 +1315,7 @@@ class PokemonFlavorText(TableBase)
          info=dict(description=u"ID of the Pokémon"))
      version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
          info=dict(description=u"ID of the version that has this flavor text"))
-     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False,
+     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
          info=dict(description="The language"))
      flavor_text = Column(Unicode(255), nullable=False,
          info=dict(description=u"The flavor text", official=True, format='gametext'))
@@@ -1328,7 -1325,7 +1328,7 @@@ class PokemonForm(TableBase)
      """
      __tablename__ = 'pokemon_forms'
      __singlename__ = 'pokemon_form'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u'A unique ID for this form.'))
      identifier = Column(Unicode(16), nullable=True,
          info=dict(description=u"An identifier", format='identifier'))
          if not self.name:
              return None
          elif self.form_group and self.form_group.term:
-             return u'{0} {1}'.format(self.name, self.form_group.term)
+             return u'%s %s' % (self.name, self.form_group.term)
          else:
              return self.name
  
          """
  
          if self.name:
-             return u'{0} {1}'.format(self.name, self.form_base_pokemon.name)
+             return u'%s %s' % (self.name, self.form_base_pokemon.name)
          else:
              return self.form_base_pokemon.name
  
@@@ -1392,7 -1389,7 +1392,7 @@@ PokemonFormGroup.id = PokemonFormGroup.
  create_translation_table('pokemon_form_group_prose', PokemonFormGroup, 'prose',
      term = Column(Unicode(16), nullable=True,
          info=dict(description=u"The term for this Pokémon's forms, e.g. \"Cloak\" for Burmy or \"Forme\" for Deoxys.", official=True, format='plaintext')),
 -    description = Column(markdown.MarkdownColumn(1024), nullable=False,
 +    description = Column(markdown.MarkdownColumn(1024), nullable=True,
          info=dict(description=u"Description of how the forms work", format='markdown')),
  )
  
@@@ -1484,9 -1481,9 +1484,9 @@@ class PokemonMoveMethod(TableBase)
  
  create_translation_table('pokemon_move_method_prose', PokemonMoveMethod, 'prose',
      relation_lazy='joined',
 -    name = Column(Unicode(64), nullable=False, index=True,
 +    name = Column(Unicode(64), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=False)),
 -    description = Column(Unicode(255), nullable=False,
 +    description = Column(Unicode(255), nullable=True,
          info=dict(description=u"A detailed description of how the method works", format='plaintext')),
  )
  
@@@ -1495,16 -1492,16 +1495,16 @@@ class PokemonShape(TableBase)
      """
      __tablename__ = 'pokemon_shapes'
      __singlename__ = 'pokemon_shape'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"A numeric ID"))
      identifier = Column(Unicode(24), nullable=False,
          info=dict(description=u"An identifier", format='identifier'))
  
  create_translation_table('pokemon_shape_prose', PokemonShape, 'prose',
      relation_lazy='joined',
 -    name = Column(Unicode(24), nullable=False, index=True,
 +    name = Column(Unicode(24), nullable=True, index=True,
          info=dict(description="The name", format='plaintext', official=False)),
 -    awesome_name = Column(Unicode(16), nullable=False,
 +    awesome_name = Column(Unicode(16), nullable=True,
          info=dict(description=u"A splendiferous name of the body shape", format='plaintext')),
  )
  
@@@ -1537,7 -1534,7 +1537,7 @@@ class Region(TableBase)
      """
      __tablename__ = 'regions'
      __singlename__ = 'region'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"A numeric ID"))
      identifier = Column(Unicode(16), nullable=False,
          info=dict(description=u"An identifier", format='identifier'))
@@@ -1553,7 -1550,7 +1553,7 @@@ class Stat(TableBase)
      """
      __tablename__ = 'stats'
      __singlename__ = 'stat'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"A numeric ID"))
      damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=True,
          info=dict(description=u"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
@@@ -1574,7 -1571,7 +1574,7 @@@ class StatHint(TableBase)
      """
      __tablename__ = 'stat_hints'
      __singlename__ = 'stat_hint'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"A numeric ID"))
      stat_id = Column(Integer, ForeignKey('stats.id'), nullable=False,
          info=dict(description=u"ID of the highest stat"))
@@@ -1601,7 -1598,7 +1601,7 @@@ class SuperContestEffect(TableBase)
      """
      __tablename__ = 'super_contest_effects'
      __singlename__ = 'super_contest_effect'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"This effect's unique ID."))
      appeal = Column(SmallInteger, nullable=False,
          info=dict(description=u"The number of hearts the user gains."))
@@@ -1615,7 -1612,7 +1615,7 @@@ class Type(TableBase)
      u"""Any of the elemental types Pokémon and moves can have."""
      __tablename__ = 'types'
      __singlename__ = 'type'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"A unique ID for this type."))
      identifier = Column(Unicode(12), nullable=False,
          info=dict(description=u"An identifier", format='identifier'))
@@@ -1646,7 -1643,7 +1646,7 @@@ class Version(TableBase)
      u"""An individual main-series Pokémon game."""
      __tablename__ = 'versions'
      __singlename__ = 'version'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"A unique ID for this version."))
      version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
          info=dict(description=u"The ID of the version group this game belongs to."))
@@@ -1664,7 -1661,7 +1664,7 @@@ class VersionGroup(TableBase)
      and Blue) or a single game (such as Yellow.)
      """
      __tablename__ = 'version_groups'
-     id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
+     id = Column(Integer, primary_key=True, nullable=False,
          info=dict(description=u"This version group's unique ID."))
      generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
          info=dict(description=u"The ID of the generation the games in this group belong to."))
  class VersionGroupRegion(TableBase):
      u"""Maps a version group to a region that appears in it."""
      __tablename__ = 'version_group_regions'
-     version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
+     version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
          info=dict(description=u"The ID of the version group."))
-     region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False, autoincrement=False,
+     region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
          info=dict(description=u"The ID of the region."))
  
  
@@@ -1747,7 -1744,7 +1747,7 @@@ EncounterConditionValueMap.condition_va
      innerjoin=True, lazy='joined',
      backref='encounter_map')
  
- EncounterSlot.terrain = relation(EncounterTerrain,
+ EncounterSlot.method = relation(EncounterMethod,
      innerjoin=True, lazy='joined',
      backref='slots')
  EncounterSlot.version_group = relation(VersionGroup, innerjoin=True)
@@@ -1824,6 -1821,12 +1824,12 @@@ LocationArea.location = relation(Locati
      innerjoin=True, lazy='joined',
      backref='areas')
  
+ LocationAreaEncounterRate.location_area = relation(LocationArea,
+     innerjoin=True,
+     backref='encounter_rates')
+ LocationAreaEncounterRate.method = relation(EncounterMethod,
+     innerjoin=True)
  LocationGameIndex.location = relation(Location,
      innerjoin=True, lazy='joined',
      backref='game_indices')