mirror of
https://github.com/veekun/pokedex.git
synced 2024-08-20 18:16:34 +00:00
Merge remote-tracking branch 'origin/encounters-i18n'
Conflicts: pokedex/db/__init__.py
This commit is contained in:
commit
905f5b3d13
27 changed files with 12048 additions and 437 deletions
|
@ -1,287 +0,0 @@
|
|||
# encoding: utf8
|
||||
from optparse import OptionParser
|
||||
import os
|
||||
import sys
|
||||
|
||||
# XXX importing pokedex.whatever should not import all these
|
||||
import pokedex.db
|
||||
import pokedex.db.load
|
||||
import pokedex.db.tables
|
||||
import pokedex.lookup
|
||||
from pokedex import defaults
|
||||
|
||||
def main():
|
||||
if len(sys.argv) <= 1:
|
||||
command_help()
|
||||
|
||||
command = sys.argv[1]
|
||||
args = sys.argv[2:]
|
||||
|
||||
# XXX there must be a better way to get Unicode argv
|
||||
# XXX this doesn't work on Windows durp
|
||||
enc = sys.stdin.encoding or 'utf8'
|
||||
args = [_.decode(enc) for _ in args]
|
||||
|
||||
# Find the command as a function in this file
|
||||
func = globals().get("command_%s" % command, None)
|
||||
if func:
|
||||
func(*args)
|
||||
else:
|
||||
command_help()
|
||||
|
||||
|
||||
def get_parser(verbose=True):
|
||||
"""Returns an OptionParser prepopulated with the global options.
|
||||
|
||||
`verbose` is whether or not the options should be verbose by default.
|
||||
"""
|
||||
parser = OptionParser()
|
||||
parser.add_option('-e', '--engine', dest='engine_uri', default=None)
|
||||
parser.add_option('-i', '--index', dest='index_dir', default=None)
|
||||
parser.add_option('-q', '--quiet', dest='verbose', default=verbose, action='store_false')
|
||||
parser.add_option('-v', '--verbose', dest='verbose', default=verbose, action='store_true')
|
||||
return parser
|
||||
|
||||
def get_session(options):
|
||||
"""Given a parsed options object, connects to the database and returns a
|
||||
session.
|
||||
"""
|
||||
|
||||
engine_uri = options.engine_uri
|
||||
got_from = 'command line'
|
||||
|
||||
if engine_uri is None:
|
||||
engine_uri, got_from = defaults.get_default_db_uri_with_origin()
|
||||
|
||||
session = pokedex.db.connect(engine_uri)
|
||||
|
||||
if options.verbose:
|
||||
print "Connected to database %(engine)s (from %(got_from)s)" \
|
||||
% dict(engine=session.bind.url, got_from=got_from)
|
||||
|
||||
return session
|
||||
|
||||
def get_lookup(options, session=None, recreate=False):
|
||||
"""Given a parsed options object, opens the whoosh index and returns a
|
||||
PokedexLookup object.
|
||||
"""
|
||||
|
||||
if recreate and not session:
|
||||
raise ValueError("get_lookup() needs an explicit session to regen the index")
|
||||
|
||||
index_dir = options.index_dir
|
||||
got_from = 'command line'
|
||||
|
||||
if index_dir is None:
|
||||
index_dir, got_from = defaults.get_default_index_dir_with_origin()
|
||||
|
||||
if options.verbose:
|
||||
print "Opened lookup index %(index_dir)s (from %(got_from)s)" \
|
||||
% dict(index_dir=index_dir, got_from=got_from)
|
||||
|
||||
lookup = pokedex.lookup.PokedexLookup(index_dir, session=session)
|
||||
|
||||
if recreate:
|
||||
lookup.rebuild_index()
|
||||
|
||||
return lookup
|
||||
|
||||
def get_csv_directory(options):
|
||||
"""Prints and returns the csv directory we're about to use."""
|
||||
|
||||
if not options.verbose:
|
||||
return
|
||||
|
||||
csvdir = options.directory
|
||||
got_from = 'command line'
|
||||
|
||||
if csvdir is None:
|
||||
csvdir, got_from = defaults.get_default_csv_dir_with_origin()
|
||||
|
||||
print "Using CSV directory %(csvdir)s (from %(got_from)s)" \
|
||||
% dict(csvdir=csvdir, got_from=got_from)
|
||||
|
||||
return csvdir
|
||||
|
||||
|
||||
### Plumbing commands
|
||||
|
||||
def command_dump(*args):
|
||||
parser = get_parser(verbose=True)
|
||||
parser.add_option('-d', '--directory', dest='directory', default=None)
|
||||
options, tables = parser.parse_args(list(args))
|
||||
|
||||
session = get_session(options)
|
||||
get_csv_directory(options)
|
||||
|
||||
pokedex.db.load.dump(session, directory=options.directory,
|
||||
tables=tables,
|
||||
verbose=options.verbose)
|
||||
|
||||
def command_load(*args):
|
||||
parser = get_parser(verbose=True)
|
||||
parser.add_option('-d', '--directory', dest='directory', default=None)
|
||||
parser.add_option('-D', '--drop-tables', dest='drop_tables', default=False, action='store_true')
|
||||
parser.add_option('-S', '--safe', dest='safe', default=False, action='store_true',
|
||||
help="Do not use backend-specific optimalizations.")
|
||||
options, tables = parser.parse_args(list(args))
|
||||
|
||||
if not options.engine_uri:
|
||||
print "WARNING: You're reloading the default database, but not the lookup index. They"
|
||||
print " might get out of sync, and pokedex commands may not work correctly!"
|
||||
print "To fix this, run `pokedex reindex` when this command finishes. Or, just use"
|
||||
print "`pokedex setup` to do both at once."
|
||||
print
|
||||
|
||||
session = get_session(options)
|
||||
get_csv_directory(options)
|
||||
|
||||
pokedex.db.load.load(session, directory=options.directory,
|
||||
drop_tables=options.drop_tables,
|
||||
tables=tables,
|
||||
verbose=options.verbose,
|
||||
safe=options.safe)
|
||||
|
||||
def command_reindex(*args):
|
||||
parser = get_parser(verbose=True)
|
||||
options, _ = parser.parse_args(list(args))
|
||||
|
||||
session = get_session(options)
|
||||
lookup = get_lookup(options, session=session, recreate=True)
|
||||
|
||||
print "Recreated lookup index."
|
||||
|
||||
|
||||
def command_setup(*args):
|
||||
parser = get_parser(verbose=False)
|
||||
options, _ = parser.parse_args(list(args))
|
||||
|
||||
options.directory = None
|
||||
|
||||
session = get_session(options)
|
||||
get_csv_directory(options)
|
||||
pokedex.db.load.load(session, directory=None, drop_tables=True,
|
||||
verbose=options.verbose,
|
||||
safe=False)
|
||||
|
||||
lookup = get_lookup(options, session=session, recreate=True)
|
||||
|
||||
print "Recreated lookup index."
|
||||
|
||||
|
||||
def command_status(*args):
|
||||
parser = get_parser(verbose=True)
|
||||
options, _ = parser.parse_args(list(args))
|
||||
options.verbose = True
|
||||
options.directory = None
|
||||
|
||||
# Database, and a lame check for whether it's been inited at least once
|
||||
session = get_session(options)
|
||||
print " - OK! Connected successfully."
|
||||
|
||||
if pokedex.db.tables.Pokemon.__table__.exists(session.bind):
|
||||
print " - OK! Database seems to contain some data."
|
||||
else:
|
||||
print " - WARNING: Database appears to be empty."
|
||||
|
||||
# CSV; simple checks that the dir exists
|
||||
csvdir = get_csv_directory(options)
|
||||
if not os.path.exists(csvdir):
|
||||
print " - ERROR: No such directory!"
|
||||
elif not os.path.isdir(csvdir):
|
||||
print " - ERROR: Not a directory!"
|
||||
else:
|
||||
print " - OK! Directory exists."
|
||||
|
||||
if os.access(csvdir, os.R_OK):
|
||||
print " - OK! Can read from directory."
|
||||
else:
|
||||
print " - ERROR: Can't read from directory!"
|
||||
|
||||
if os.access(csvdir, os.W_OK):
|
||||
print " - OK! Can write to directory."
|
||||
else:
|
||||
print " - WARNING: Can't write to directory! " \
|
||||
"`dump` will not work. You may need to sudo."
|
||||
|
||||
# Index; the PokedexLookup constructor covers most tests and will
|
||||
# cheerfully bomb if they fail
|
||||
lookup = get_lookup(options, recreate=False)
|
||||
print " - OK! Opened successfully."
|
||||
|
||||
|
||||
### User-facing commands
|
||||
|
||||
def command_lookup(*args):
|
||||
parser = get_parser(verbose=False)
|
||||
options, words = parser.parse_args(list(args))
|
||||
|
||||
name = u' '.join(words)
|
||||
|
||||
session = get_session(options)
|
||||
lookup = get_lookup(options, session=session, recreate=False)
|
||||
|
||||
results = lookup.lookup(name)
|
||||
if not results:
|
||||
print "No matches."
|
||||
elif results[0].exact:
|
||||
print "Matched:"
|
||||
else:
|
||||
print "Fuzzy-matched:"
|
||||
|
||||
for result in results:
|
||||
if hasattr(result.object, 'full_name'):
|
||||
name = result.object.full_name
|
||||
else:
|
||||
name = result.object.name
|
||||
|
||||
print "%s: %s" % (result.object.__tablename__, name),
|
||||
if result.language:
|
||||
print "(%s in %s)" % (result.name, result.language)
|
||||
else:
|
||||
print
|
||||
|
||||
|
||||
def command_help():
|
||||
print u"""pokedex -- a command-line Pokédex interface
|
||||
usage: pokedex {command} [options...]
|
||||
Run `pokedex setup` first, or nothing will work!
|
||||
See http://bugs.veekun.com/projects/pokedex/wiki/CLI for more documentation.
|
||||
|
||||
Commands:
|
||||
help Displays this message.
|
||||
lookup [thing] Look up something in the Pokédex.
|
||||
|
||||
System commands:
|
||||
load Load Pokédex data into a database from CSV files.
|
||||
dump Dump Pokédex data from a database into CSV files.
|
||||
reindex Rebuilds the lookup index from the database.
|
||||
setup Combines load and reindex.
|
||||
status No effect, but prints which engine, index, and csv
|
||||
directory would be used for other commands.
|
||||
|
||||
Global options:
|
||||
-e|--engine=URI By default, all commands try to use a SQLite database
|
||||
in the pokedex install directory. Use this option (or
|
||||
a POKEDEX_DB_ENGINE environment variable) to specify an
|
||||
alternate database.
|
||||
-i|--index=DIR By default, all commands try to put the lookup index in
|
||||
the pokedex install directory. Use this option (or a
|
||||
POKEDEX_INDEX_DIR environment variable) to specify an
|
||||
alternate loction.
|
||||
-q|--quiet Don't print system output. This is the default for
|
||||
non-system commands and setup.
|
||||
-v|--verbose Print system output. This is the default for system
|
||||
commands, except setup.
|
||||
|
||||
System options:
|
||||
-d|--directory=DIR By default, load and dump will use the CSV files in the
|
||||
pokedex install directory. Use this option to specify
|
||||
a different directory.
|
||||
-D|--drop-tables With load, drop all tables before loading data.
|
||||
|
||||
Additionally, load and dump accept a list of table names (possibly with
|
||||
wildcards) and/or csv fileames as an argument list.
|
||||
""".encode(sys.getdefaultencoding(), 'replace')
|
||||
|
||||
sys.exit(0)
|
|
@ -1,16 +1,16 @@
|
|||
id,identifier
|
||||
1,monster
|
||||
2,water-1
|
||||
2,water1
|
||||
3,bug
|
||||
4,flying
|
||||
5,ground
|
||||
6,fairy
|
||||
7,plant
|
||||
8,humanshape
|
||||
9,water-3
|
||||
9,water3
|
||||
10,mineral
|
||||
11,indeterminate
|
||||
12,water-2
|
||||
12,water2
|
||||
13,ditto
|
||||
14,dragon
|
||||
15,no-eggs
|
||||
|
|
|
|
@ -1,17 +1,17 @@
|
|||
id,encounter_condition_id,identifier,is_default
|
||||
1,1,during-a-swarm,0
|
||||
2,1,not-during-a-swarm,1
|
||||
3,2,in-the-morning,0
|
||||
4,2,during-the-day,1
|
||||
5,2,at-night,0
|
||||
6,3,using-pokeradar,0
|
||||
7,3,not-using-pokeradar,1
|
||||
8,4,no-game-in-slot-2,1
|
||||
9,4,ruby-in-slot-2,0
|
||||
10,4,sapphire-in-slot-2,0
|
||||
11,4,emerald-in-slot-2,0
|
||||
12,4,firered-in-slot-2,0
|
||||
13,4,leafgreen-in-slot-2,0
|
||||
1,1,swarm-yes,0
|
||||
2,1,swarm-no,1
|
||||
3,2,time-morning,0
|
||||
4,2,time-day,1
|
||||
5,2,time-night,0
|
||||
6,3,radar-on,0
|
||||
7,3,radar-off,1
|
||||
8,4,slot2-none,1
|
||||
9,4,slot2-ruby,0
|
||||
10,4,slot2-sapphire,0
|
||||
11,4,slot2-emerald,0
|
||||
12,4,slot2-firered,0
|
||||
13,4,slot2-leafgreen,0
|
||||
14,5,radio-off,1
|
||||
15,5,hoenn-radio,0
|
||||
16,5,sinnoh-radio,0
|
||||
15,5,radio-hoenn,0
|
||||
16,5,radio-sinnoh,0
|
||||
|
|
|
|
@ -1,6 +1,6 @@
|
|||
id,identifier
|
||||
1,swarm
|
||||
2,time-of-day
|
||||
3,pokeradar
|
||||
4,gen-3-game-in-slot-2
|
||||
2,time
|
||||
3,radar
|
||||
4,slot2
|
||||
5,radio
|
||||
|
|
|
|
@ -1,4 +1,4 @@
|
|||
encounter_terrain_id,local_language_id,name
|
||||
encounter_method_id,local_language_id,name
|
||||
1,9,Walking in tall grass or a cave
|
||||
2,9,Fishing with an Old Rod
|
||||
3,9,Fishing with a Good Rod
|
|
8
pokedex/data/csv/encounter_methods.csv
Normal file
8
pokedex/data/csv/encounter_methods.csv
Normal file
|
@ -0,0 +1,8 @@
|
|||
id,identifier
|
||||
1,walk
|
||||
2,old-rod
|
||||
3,good-rod
|
||||
4,super-rod
|
||||
5,surf
|
||||
6,rock-smash
|
||||
7,headbutt
|
|
|
@ -1,4 +1,4 @@
|
|||
id,version_group_id,encounter_terrain_id,slot,rarity
|
||||
id,version_group_id,encounter_method_id,slot,rarity
|
||||
1,8,1,1,20
|
||||
2,8,1,2,20
|
||||
3,8,1,3,10
|
||||
|
@ -153,3 +153,99 @@ id,version_group_id,encounter_terrain_id,slot,rarity
|
|||
152,9,5,3,5
|
||||
153,9,5,4,4
|
||||
154,9,5,5,1
|
||||
155,5,3,1,60
|
||||
156,5,3,2,20
|
||||
157,5,3,3,20
|
||||
158,5,2,1,70
|
||||
159,5,2,2,30
|
||||
160,5,4,1,40
|
||||
161,5,4,2,40
|
||||
162,5,4,3,15
|
||||
163,5,4,4,4
|
||||
164,5,4,5,1
|
||||
165,5,5,1,60
|
||||
166,5,5,2,30
|
||||
167,5,5,3,5
|
||||
168,5,5,4,4
|
||||
169,5,5,5,1
|
||||
170,5,1,1,20
|
||||
171,5,1,2,20
|
||||
172,5,1,3,10
|
||||
173,5,1,4,10
|
||||
174,5,1,5,10
|
||||
175,5,1,6,10
|
||||
176,5,1,7,5
|
||||
177,5,1,8,5
|
||||
178,5,1,9,4
|
||||
179,5,1,10,4
|
||||
180,5,1,11,1
|
||||
181,5,1,12,1
|
||||
182,5,6,1,60
|
||||
183,5,6,2,30
|
||||
184,5,6,3,5
|
||||
185,5,6,4,4
|
||||
186,5,6,5,1
|
||||
187,6,1,1,20
|
||||
188,6,1,2,20
|
||||
189,6,1,3,10
|
||||
190,6,1,4,10
|
||||
191,6,1,5,10
|
||||
192,6,1,6,10
|
||||
193,6,1,7,5
|
||||
194,6,1,8,5
|
||||
195,6,1,9,4
|
||||
196,6,1,10,4
|
||||
197,6,1,11,1
|
||||
198,6,1,12,1
|
||||
199,6,3,1,60
|
||||
200,6,3,2,20
|
||||
201,6,3,3,20
|
||||
202,6,2,1,70
|
||||
203,6,2,2,30
|
||||
204,6,4,1,40
|
||||
205,6,4,2,40
|
||||
206,6,4,3,15
|
||||
207,6,4,4,4
|
||||
208,6,4,5,1
|
||||
209,6,5,1,60
|
||||
210,6,5,2,30
|
||||
211,6,5,3,5
|
||||
212,6,5,4,4
|
||||
213,6,5,5,1
|
||||
214,6,6,1,60
|
||||
215,6,6,2,30
|
||||
216,6,6,3,5
|
||||
217,6,6,4,4
|
||||
218,6,6,5,1
|
||||
219,7,1,1,20
|
||||
220,7,1,2,20
|
||||
221,7,1,3,10
|
||||
222,7,1,4,10
|
||||
223,7,1,5,10
|
||||
224,7,1,6,10
|
||||
225,7,1,7,5
|
||||
226,7,1,8,5
|
||||
227,7,1,9,4
|
||||
228,7,1,10,4
|
||||
229,7,1,11,1
|
||||
230,7,1,12,1
|
||||
231,7,3,1,60
|
||||
232,7,3,2,20
|
||||
233,7,3,3,20
|
||||
234,7,2,1,70
|
||||
235,7,2,2,30
|
||||
236,7,4,1,40
|
||||
237,7,4,2,40
|
||||
238,7,4,3,15
|
||||
239,7,4,4,4
|
||||
240,7,4,5,1
|
||||
241,7,5,1,60
|
||||
242,7,5,2,30
|
||||
243,7,5,3,5
|
||||
244,7,5,4,4
|
||||
245,7,5,5,1
|
||||
246,7,6,1,60
|
||||
247,7,6,2,30
|
||||
248,7,6,3,5
|
||||
249,7,6,4,4
|
||||
250,7,6,5,1
|
||||
|
|
|
|
@ -1,8 +0,0 @@
|
|||
id,identifier
|
||||
1,walking-in-tall-grass-or-a-cave
|
||||
2,fishing-with-an-old-rod
|
||||
3,fishing-with-a-good-rod
|
||||
4,fishing-with-a-super-rod
|
||||
5,surfing
|
||||
6,smashing-rocks
|
||||
7,headbutting-trees
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -304,3 +304,229 @@ location_area_id,local_language_id,name
|
|||
347,9,"Area 2, north"
|
||||
348,9,"Area 3, west"
|
||||
349,9,S.S. Anne dock
|
||||
350,9,
|
||||
351,9,
|
||||
352,9,
|
||||
353,9,
|
||||
354,9,
|
||||
355,9,
|
||||
356,9,
|
||||
357,9,back
|
||||
358,9,B1F
|
||||
359,9,back/small room
|
||||
360,9,
|
||||
361,9,1F
|
||||
362,9,B1F
|
||||
363,9,B2F
|
||||
364,9,1F/small Room
|
||||
365,9,
|
||||
366,9,
|
||||
367,9,
|
||||
368,9,1F
|
||||
369,9,2F
|
||||
370,9,3F
|
||||
371,9,4F
|
||||
372,9,5F
|
||||
373,9,6F
|
||||
374,9,outside
|
||||
375,9,summit
|
||||
376,9,
|
||||
377,9,entrance
|
||||
378,9,1F
|
||||
379,9,B1F
|
||||
380,9,B2F
|
||||
381,9,B3F
|
||||
382,9,1F
|
||||
383,9,B1F
|
||||
384,9,B2F
|
||||
385,9,
|
||||
386,9,B1F
|
||||
387,9,Entrance
|
||||
388,9,
|
||||
389,9,
|
||||
390,9,1F
|
||||
391,9,3F
|
||||
392,9,5F
|
||||
393,9,
|
||||
394,9,
|
||||
395,9,
|
||||
396,9,
|
||||
397,9,
|
||||
398,9,
|
||||
399,9,
|
||||
400,9,
|
||||
401,9,
|
||||
402,9,
|
||||
403,9,
|
||||
404,9,
|
||||
405,9,
|
||||
406,9,
|
||||
407,9,
|
||||
408,9,
|
||||
409,9,
|
||||
410,9,
|
||||
411,9,
|
||||
412,9,
|
||||
413,9,
|
||||
414,9,
|
||||
415,9,
|
||||
416,9,
|
||||
417,9,underwater
|
||||
418,9,
|
||||
419,9,
|
||||
420,9,underwater
|
||||
421,9,
|
||||
422,9,
|
||||
423,9,
|
||||
424,9,
|
||||
425,9,
|
||||
426,9,
|
||||
427,9,
|
||||
428,9,
|
||||
429,9,NW/mach bike area
|
||||
430,9,NE/acro bike area
|
||||
431,9,SW
|
||||
432,9,SE
|
||||
433,9,
|
||||
434,9,
|
||||
435,9,expansion south
|
||||
436,9,expansion north
|
||||
437,9,
|
||||
438,9,
|
||||
439,9,
|
||||
440,9,
|
||||
441,9,a
|
||||
442,9,b
|
||||
443,9,c
|
||||
444,9,d
|
||||
445,9,e
|
||||
446,9,f
|
||||
447,9,g
|
||||
448,9,h
|
||||
449,9,i
|
||||
450,9,
|
||||
451,9,
|
||||
452,9,
|
||||
453,9,
|
||||
454,9,
|
||||
455,9,
|
||||
456,9,
|
||||
457,9,
|
||||
458,9,1F
|
||||
459,9,B1F
|
||||
460,9,B2F
|
||||
461,9,
|
||||
462,9,
|
||||
463,9,1F
|
||||
464,9,2F
|
||||
465,9,3F
|
||||
466,9,
|
||||
467,9,B1F
|
||||
468,9,center
|
||||
469,9,"Area 1, east"
|
||||
470,9,"Area 2, north"
|
||||
471,9,"Area 3, west"
|
||||
472,9,1F
|
||||
473,9,2F
|
||||
474,9,B1F
|
||||
475,9,1F
|
||||
476,9,B1F
|
||||
477,9,1F
|
||||
478,9,B1F
|
||||
479,9,B2F
|
||||
480,9,B3F
|
||||
481,9,B4F
|
||||
482,9,3F
|
||||
483,9,4F
|
||||
484,9,5F
|
||||
485,9,6F
|
||||
486,9,7F
|
||||
487,9,
|
||||
488,9,
|
||||
489,9,cave
|
||||
490,9,inside
|
||||
491,9,"1F, cave behind team rocket"
|
||||
492,9,B1F
|
||||
493,9,B2F
|
||||
494,9,B3F
|
||||
495,9,
|
||||
496,9,entrance
|
||||
497,9,1F
|
||||
498,9,B1F
|
||||
499,9,waterfall
|
||||
500,9,
|
||||
501,9,room 1
|
||||
502,9,room 2
|
||||
503,9,room 3
|
||||
504,9,room 4
|
||||
505,9,room 5
|
||||
506,9,room 6
|
||||
507,9,room 7
|
||||
508,9,room 8
|
||||
509,9,room 9
|
||||
510,9,room 10
|
||||
511,9,item rooms
|
||||
512,9,
|
||||
513,9,
|
||||
514,9,
|
||||
515,9,
|
||||
516,9,
|
||||
517,9,
|
||||
518,9,
|
||||
519,9,
|
||||
520,9,
|
||||
521,9,
|
||||
522,9,
|
||||
523,9,
|
||||
524,9,
|
||||
525,9,
|
||||
526,9,
|
||||
527,9,
|
||||
528,9,
|
||||
529,9,
|
||||
530,9,
|
||||
531,9,
|
||||
532,9,
|
||||
533,9,
|
||||
534,9,
|
||||
535,9,
|
||||
536,9,
|
||||
537,9,
|
||||
538,9,
|
||||
539,9,
|
||||
540,9,
|
||||
541,9,
|
||||
542,9,
|
||||
543,9,
|
||||
544,9,
|
||||
545,9,
|
||||
546,9,
|
||||
547,9,
|
||||
548,9,
|
||||
549,9,
|
||||
550,9,
|
||||
551,9,
|
||||
552,9,
|
||||
553,9,
|
||||
554,9,
|
||||
555,9,
|
||||
556,9,
|
||||
557,9,
|
||||
558,9,
|
||||
559,9,
|
||||
560,9,
|
||||
561,9,
|
||||
562,9,
|
||||
563,9,
|
||||
564,9,a
|
||||
565,9,b
|
||||
566,9,c
|
||||
567,9,d
|
||||
568,9,e
|
||||
569,9,f
|
||||
570,9,g
|
||||
571,9,h
|
||||
572,9,i
|
||||
573,9,1F
|
||||
574,9,2F
|
||||
575,9,3F
|
||||
|
|
|
|
@ -304,3 +304,229 @@ id,location_id,game_index,identifier
|
|||
347,162,0,area-2-north
|
||||
348,162,0,area-3-west
|
||||
349,151,0,ss-anne-dock
|
||||
350,429,0,
|
||||
351,430,1,
|
||||
352,431,2,
|
||||
353,432,3,
|
||||
354,433,4,
|
||||
355,434,5,
|
||||
356,435,6,
|
||||
357,435,7,back
|
||||
358,435,8,b1f
|
||||
359,435,9,backsmall-room
|
||||
360,436,10,
|
||||
361,437,11,1f
|
||||
362,437,12,b1f
|
||||
363,437,13,b2f
|
||||
364,437,14,1fsmall-room
|
||||
365,438,15,
|
||||
366,439,16,
|
||||
367,440,17,
|
||||
368,441,18,1f
|
||||
369,441,19,2f
|
||||
370,441,20,3f
|
||||
371,441,21,4f
|
||||
372,441,22,5f
|
||||
373,441,23,6f
|
||||
374,441,24,outside
|
||||
375,441,25,summit
|
||||
376,442,26,
|
||||
377,443,35,entrance
|
||||
378,443,36,1f
|
||||
379,443,37,b1f
|
||||
380,443,38,b2f
|
||||
381,443,39,b3f
|
||||
382,444,40,1f
|
||||
383,444,41,b1f
|
||||
384,444,42,b2f
|
||||
385,445,43,
|
||||
386,445,47,b1f
|
||||
387,446,48,entrance
|
||||
388,446,49,
|
||||
389,447,50,
|
||||
390,448,52,1f
|
||||
391,448,53,3f
|
||||
392,448,54,5f
|
||||
393,449,55,
|
||||
394,450,56,
|
||||
395,451,57,
|
||||
396,452,58,
|
||||
397,453,59,
|
||||
398,454,60,
|
||||
399,455,61,
|
||||
400,456,62,
|
||||
401,457,63,
|
||||
402,458,64,
|
||||
403,459,65,
|
||||
404,460,66,
|
||||
405,461,67,
|
||||
406,462,68,
|
||||
407,463,69,
|
||||
408,464,70,
|
||||
409,465,71,
|
||||
410,466,72,
|
||||
411,467,73,
|
||||
412,468,74,
|
||||
413,469,75,
|
||||
414,470,76,
|
||||
415,471,77,
|
||||
416,472,78,
|
||||
417,472,95,underwater
|
||||
418,473,79,
|
||||
419,474,80,
|
||||
420,474,96,underwater
|
||||
421,475,81,
|
||||
422,476,82,
|
||||
423,477,83,
|
||||
424,478,84,
|
||||
425,479,85,
|
||||
426,480,86,
|
||||
427,481,87,
|
||||
428,482,88,
|
||||
429,483,89,nwmach-bike-area
|
||||
430,483,90,neacro-bike-area
|
||||
431,483,91,sw
|
||||
432,483,92,se
|
||||
433,484,93,
|
||||
434,485,94,
|
||||
435,483,97,expansion-south
|
||||
436,483,98,expansion-north
|
||||
437,486,99,
|
||||
438,487,107,
|
||||
439,488,111,
|
||||
440,489,112,
|
||||
441,490,114,a
|
||||
442,490,115,b
|
||||
443,490,116,c
|
||||
444,490,117,d
|
||||
445,490,118,e
|
||||
446,490,119,f
|
||||
447,490,120,g
|
||||
448,490,121,h
|
||||
449,490,122,i
|
||||
450,491,0,
|
||||
451,492,1,
|
||||
452,493,2,
|
||||
453,494,3,
|
||||
454,495,4,
|
||||
455,496,5,
|
||||
456,497,6,
|
||||
457,155,7,
|
||||
458,80,8,1f
|
||||
459,80,9,b1f
|
||||
460,80,10,b2f
|
||||
461,498,11,
|
||||
462,73,12,
|
||||
463,499,13,1f
|
||||
464,499,14,2f
|
||||
465,499,15,3f
|
||||
466,161,16,
|
||||
467,161,19,b1f
|
||||
468,162,20,center
|
||||
469,162,21,area-1-east
|
||||
470,162,22,area-2-north
|
||||
471,162,23,area-3-west
|
||||
472,147,24,1f
|
||||
473,147,25,2f
|
||||
474,147,26,b1f
|
||||
475,87,27,1f
|
||||
476,87,28,b1f
|
||||
477,136,29,1f
|
||||
478,136,30,b1f
|
||||
479,136,31,b2f
|
||||
480,136,32,b3f
|
||||
481,136,33,b4f
|
||||
482,160,34,3f
|
||||
483,160,35,4f
|
||||
484,160,36,5f
|
||||
485,160,37,6f
|
||||
486,160,38,7f
|
||||
487,158,39,
|
||||
488,500,40,
|
||||
489,500,41,cave
|
||||
490,500,42,inside
|
||||
491,500,44,1f-cave-behind-team-rocket
|
||||
492,500,45,b1f
|
||||
493,500,46,b2f
|
||||
494,500,47,b3f
|
||||
495,501,50,
|
||||
496,502,51,entrance
|
||||
497,502,52,1f
|
||||
498,502,53,b1f
|
||||
499,502,54,waterfall
|
||||
500,503,55,
|
||||
501,504,56,room-1
|
||||
502,504,57,room-2
|
||||
503,504,58,room-3
|
||||
504,504,59,room-4
|
||||
505,504,60,room-5
|
||||
506,504,61,room-6
|
||||
507,504,62,room-7
|
||||
508,504,63,room-8
|
||||
509,504,64,room-9
|
||||
510,504,65,room-10
|
||||
511,504,66,item-rooms
|
||||
512,505,70,
|
||||
513,506,71,
|
||||
514,507,72,
|
||||
515,508,73,
|
||||
516,509,74,
|
||||
517,510,75,
|
||||
518,511,76,
|
||||
519,512,77,
|
||||
520,513,78,
|
||||
521,514,79,
|
||||
522,515,80,
|
||||
523,516,81,
|
||||
524,517,82,
|
||||
525,518,83,
|
||||
526,519,84,
|
||||
527,520,85,
|
||||
528,521,86,
|
||||
529,88,87,
|
||||
530,99,88,
|
||||
531,109,89,
|
||||
532,120,90,
|
||||
533,130,91,
|
||||
534,131,92,
|
||||
535,132,93,
|
||||
536,133,94,
|
||||
537,134,95,
|
||||
538,89,96,
|
||||
539,90,97,
|
||||
540,91,98,
|
||||
541,92,99,
|
||||
542,93,100,
|
||||
543,94,101,
|
||||
544,95,102,
|
||||
545,96,103,
|
||||
546,97,104,
|
||||
547,522,105,
|
||||
548,523,106,
|
||||
549,524,107,
|
||||
550,102,109,
|
||||
551,157,110,
|
||||
552,103,111,
|
||||
553,104,112,
|
||||
554,86,113,
|
||||
555,154,114,
|
||||
556,68,115,
|
||||
557,525,116,
|
||||
558,67,117,
|
||||
559,76,118,
|
||||
560,71,119,
|
||||
561,526,120,
|
||||
562,527,121,
|
||||
563,528,122,
|
||||
564,529,123,a
|
||||
565,529,124,b
|
||||
566,529,125,c
|
||||
567,529,126,d
|
||||
568,529,127,e
|
||||
569,529,128,f
|
||||
570,529,129,g
|
||||
571,529,130,h
|
||||
572,529,131,i
|
||||
573,530,13,1f
|
||||
574,530,14,2f
|
||||
575,530,15,3f
|
||||
|
|
|
|
@ -324,3 +324,118 @@ location_id,generation_id,game_index
|
|||
341,4,3076
|
||||
342,4,2013
|
||||
343,4,2014
|
||||
344,5,1
|
||||
345,5,2
|
||||
346,5,4
|
||||
346,5,81
|
||||
347,5,5
|
||||
348,5,6
|
||||
349,5,7
|
||||
350,5,8
|
||||
351,5,9
|
||||
351,5,76
|
||||
352,5,10
|
||||
352,5,77
|
||||
353,5,11
|
||||
353,5,78
|
||||
354,5,12
|
||||
354,5,79
|
||||
355,5,13
|
||||
355,5,80
|
||||
356,5,14
|
||||
357,5,15
|
||||
358,5,16
|
||||
359,5,17
|
||||
360,5,18
|
||||
360,5,93
|
||||
361,5,19
|
||||
361,5,94
|
||||
362,5,20
|
||||
362,5,95
|
||||
363,5,21
|
||||
363,5,96
|
||||
364,5,22
|
||||
364,5,97
|
||||
365,5,23
|
||||
366,5,24
|
||||
366,5,98
|
||||
367,5,25
|
||||
367,5,99
|
||||
368,5,26
|
||||
368,5,100
|
||||
369,5,27
|
||||
369,5,101
|
||||
370,5,28
|
||||
370,5,102
|
||||
371,5,29
|
||||
371,5,103
|
||||
372,5,30
|
||||
373,5,31
|
||||
374,5,32
|
||||
375,5,33
|
||||
376,5,34
|
||||
377,5,35
|
||||
378,5,36
|
||||
378,5,84
|
||||
379,5,37
|
||||
379,5,85
|
||||
380,5,38
|
||||
380,5,86
|
||||
381,5,39
|
||||
381,5,87
|
||||
382,5,40
|
||||
383,5,41
|
||||
383,5,104
|
||||
384,5,42
|
||||
384,5,105
|
||||
385,5,43
|
||||
386,5,44
|
||||
387,5,45
|
||||
388,5,46
|
||||
389,5,47
|
||||
390,5,48
|
||||
391,5,49
|
||||
392,5,50
|
||||
392,5,83
|
||||
393,5,51
|
||||
393,5,82
|
||||
394,5,52
|
||||
395,5,53
|
||||
396,5,54
|
||||
397,5,55
|
||||
398,5,56
|
||||
399,5,57
|
||||
400,5,58
|
||||
401,5,59
|
||||
402,5,60
|
||||
403,5,61
|
||||
403,5,88
|
||||
404,5,62
|
||||
405,5,63
|
||||
406,5,64
|
||||
407,5,65
|
||||
407,5,89
|
||||
408,5,66
|
||||
408,5,90
|
||||
409,5,67
|
||||
409,5,91
|
||||
410,5,68
|
||||
410,5,92
|
||||
411,5,69
|
||||
412,5,70
|
||||
413,5,71
|
||||
414,5,72
|
||||
415,5,73
|
||||
416,5,74
|
||||
417,5,75
|
||||
418,5,106
|
||||
419,5,107
|
||||
420,5,108
|
||||
421,5,109
|
||||
422,5,110
|
||||
423,5,111
|
||||
424,5,112
|
||||
425,5,113
|
||||
426,5,114
|
||||
427,5,115
|
||||
428,5,116
|
||||
|
|
|
|
@ -331,3 +331,275 @@ location_id,local_language_id,name
|
|||
341,9,Concert Event
|
||||
342,9,Mr. Pokémon
|
||||
343,9,Primo
|
||||
344,1,なぞの場所
|
||||
344,9,Mystery Zone
|
||||
345,1,遠い場所
|
||||
345,9,Faraway place
|
||||
346,1,カノコタウン
|
||||
346,9,Nuvema Town
|
||||
347,1,カラクサタウン
|
||||
347,9,Accumula Town
|
||||
348,1,サンヨウシティ
|
||||
348,9,Striaton City
|
||||
349,1,シッポウシティ
|
||||
349,9,Nacrene City
|
||||
350,1,ヒウンシティ
|
||||
350,9,Castelia City
|
||||
351,1,ライモンシティ
|
||||
351,9,Nimbasa City
|
||||
352,1,ホドモエシティ
|
||||
352,9,Driftveil City
|
||||
353,1,フキヨセシティ
|
||||
353,9,Mistralton City
|
||||
354,1,セッカシティ
|
||||
354,9,Icirrus City
|
||||
355,1,ソウリュウシティ
|
||||
355,9,Opelucid City
|
||||
356,1,1番道路
|
||||
356,9,Route 1
|
||||
357,1,2番道路
|
||||
357,9,Route 2
|
||||
358,1,3番道路
|
||||
358,9,Route 3
|
||||
359,1,4番道路
|
||||
359,9,Route 4
|
||||
360,1,5番道路
|
||||
360,9,Route 5
|
||||
361,1,6番道路
|
||||
361,9,Route 6
|
||||
362,1,7番道路
|
||||
362,9,Route 7
|
||||
363,1,8番道路
|
||||
363,9,Route 8
|
||||
364,1,9番道路
|
||||
364,9,Route 9
|
||||
365,1,10番道路
|
||||
365,9,Route 10
|
||||
366,1,11番道路
|
||||
366,9,Route 11
|
||||
367,1,12番道路
|
||||
367,9,Route 12
|
||||
368,1,13番道路
|
||||
368,9,Route 13
|
||||
369,1,14番道路
|
||||
369,9,Route 14
|
||||
370,1,15番道路
|
||||
370,9,Route 15
|
||||
371,1,16番道路
|
||||
371,9,Route 16
|
||||
372,1,17番水道
|
||||
372,9,Route 17
|
||||
373,1,18番道路
|
||||
373,9,Route 18
|
||||
374,1,夢の跡地
|
||||
374,9,Dreamyard
|
||||
375,1,ヤグルマの森
|
||||
375,9,Pinwheel Forest
|
||||
376,1,リゾートデザート
|
||||
376,9,Desert Resort
|
||||
377,1,古代の城
|
||||
377,9,Relic Castle
|
||||
378,1,冷凍コンテナ
|
||||
378,9,Cold Storage
|
||||
379,1,電気石の洞穴
|
||||
379,9,Chargestone Cave
|
||||
380,1,ネジ山
|
||||
380,9,Twist Mountain
|
||||
381,1,リュウラセンの塔
|
||||
381,9,Dragonspiral Tower
|
||||
382,1,チャンピオンロード
|
||||
382,9,Victory Road
|
||||
383,1,カゴメタウン
|
||||
383,9,Lacunosa Town
|
||||
384,1,サザナミタウン
|
||||
384,9,Undella Town
|
||||
385,1,カナワタウン
|
||||
385,9,Anville Town
|
||||
386,1,ポケモンリーグ
|
||||
386,9,Pokémon League
|
||||
387,1,Nの城
|
||||
387,9,N's Castle
|
||||
388,1,ロイヤルイッシュ号
|
||||
388,9,Royal Unova
|
||||
389,1,ギアステーション
|
||||
389,9,Gear Station
|
||||
390,1,バトルサブウェイ
|
||||
390,9,Battle Subway
|
||||
391,1,ミュージカルホール
|
||||
391,9,Musical Theater
|
||||
392,1,ブラックシティ
|
||||
392,9,Black City
|
||||
393,1,ホワイトフォレスト
|
||||
393,9,White Forest
|
||||
394,1,ユナイテッドタワー
|
||||
394,9,Unity Tower
|
||||
395,1,地下水脈の穴
|
||||
395,9,Wellspring Cave
|
||||
396,1,フキヨセの洞穴
|
||||
396,9,Mistralton Cave
|
||||
397,1,思索の原
|
||||
397,9,Rumination Field
|
||||
398,1,タワーオブヘブン
|
||||
398,9,Celestial Tower
|
||||
399,1,セッカの湿原
|
||||
399,9,Moor of Icirrus
|
||||
400,1,ショッピングモール
|
||||
400,9,Shopping Mall
|
||||
401,1,修行の岩屋
|
||||
401,9,Challenger's Cave
|
||||
402,1,シフトファクトリー
|
||||
402,9,Poké Transfer Lab
|
||||
403,1,ジャイアントホール
|
||||
403,9,Giant Chasm
|
||||
404,1,リバティガーデン島
|
||||
404,9,Liberty Garden
|
||||
405,1,P2ラボ
|
||||
405,9,P2 Laboratory
|
||||
406,1,スカイアローブリッジ
|
||||
406,9,Skyarrow Bridge
|
||||
407,1,ホドモエの跳ね橋
|
||||
407,9,Driftveil Drawbridge
|
||||
408,1,シリンダーブリッジ
|
||||
408,9,Tubeline Bridge
|
||||
409,1,ビレッジブリッジ
|
||||
409,9,Village Bridge
|
||||
410,1,ワンダーブリッジ
|
||||
410,9,Marvelous Bridge
|
||||
411,1,ハイリンク
|
||||
411,9,Entralink
|
||||
412,1,ほうじょうの社
|
||||
412,9,Abundant Shrine
|
||||
413,1,サザナミ湾
|
||||
413,9,Undella Bay
|
||||
414,1,迷いの森
|
||||
414,9,Lostlorn Forest
|
||||
415,1,試練の室
|
||||
415,9,Trial Chamber
|
||||
416,1,導の間
|
||||
416,9,Guidance Chamber
|
||||
417,1,ハイリンクの森
|
||||
417,9,Entree Forest
|
||||
418,1,カラクサゲート
|
||||
418,9,Accumula Gate
|
||||
419,1,サザナミゲート
|
||||
419,9,Undella Gate
|
||||
420,1,シッポウゲート
|
||||
420,9,Nacrene Gate
|
||||
421,1,ヒウンゲート
|
||||
421,9,Castelia Gate
|
||||
422,1,ライモンゲート
|
||||
422,9,Nimbasa Gate
|
||||
423,1,ソウリュウゲート
|
||||
423,9,Opelucid Gate
|
||||
424,1,ブラックゲート
|
||||
424,9,Black Gate
|
||||
425,1,ホワイトゲート
|
||||
425,9,White Gate
|
||||
426,1,ブリッジゲート
|
||||
426,9,Bridge Gate
|
||||
427,1,ロードゲート
|
||||
427,9,Route Gate
|
||||
428,1,海底遺跡
|
||||
428,9,Abyssal Ruins
|
||||
429,9,Petalburg City
|
||||
430,9,Slateport City
|
||||
431,9,Lilycove City
|
||||
432,9,Mossdeep City
|
||||
433,9,Sootopolis City
|
||||
434,9,Ever Grande City
|
||||
435,9,Meteor Falls
|
||||
436,9,Rusturf Tunnel
|
||||
437,9,Granite Cave
|
||||
438,9,Petalburg Woods
|
||||
439,9,Jagged Pass
|
||||
440,9,Fiery Pass
|
||||
441,9,Mt. Pyre
|
||||
442,9,Seafloor Cavern
|
||||
443,9,Cave of Origin
|
||||
444,9,Victory Road
|
||||
445,9,Shoal Cave
|
||||
446,9,New Mauville
|
||||
447,9,Abandoned Ship
|
||||
448,9,Sky Pillar
|
||||
449,9,Route 101
|
||||
450,9,Route 102
|
||||
451,9,Route 103
|
||||
452,9,Route 104
|
||||
453,9,Route 105
|
||||
454,9,Route 106
|
||||
455,9,Route 107
|
||||
456,9,Route 108
|
||||
457,9,Route 109
|
||||
458,9,Route 110
|
||||
459,9,Route 111
|
||||
460,9,Route 112
|
||||
461,9,Route 113
|
||||
462,9,Route 114
|
||||
463,9,Route 115
|
||||
464,9,Route 116
|
||||
465,9,Route 117
|
||||
466,9,Route 118
|
||||
467,9,Route 119
|
||||
468,9,Route 120
|
||||
469,9,Route 121
|
||||
470,9,Route 122
|
||||
471,9,Route 123
|
||||
472,9,Route 124
|
||||
473,9,Route 125
|
||||
474,9,Route 126
|
||||
475,9,Route 127
|
||||
476,9,Route 128
|
||||
477,9,Route 129
|
||||
478,9,Route 130
|
||||
479,9,Route 131
|
||||
480,9,Route 132
|
||||
481,9,Route 133
|
||||
482,9,Route 134
|
||||
483,9,Safari Zone
|
||||
484,9,Dewford Town
|
||||
485,9,Pacifidlog Town
|
||||
486,9,Magma Hideout
|
||||
487,9,Mirage Tower
|
||||
488,9,Desert Underpass
|
||||
489,9,Artisan Cave
|
||||
490,9,Altering Cave
|
||||
491,9,Monean Chamber
|
||||
492,9,Liptoo Chamber
|
||||
493,9,Weepth Chamber
|
||||
494,9,Dilford Chamber
|
||||
495,9,Scufib Chamber
|
||||
496,9,Rixy Chamber
|
||||
497,9,Viapos Chamber
|
||||
498,9,S.S. Anne
|
||||
499,9,Victory Road
|
||||
500,9,Mt. Ember
|
||||
501,9,Berry Forest
|
||||
502,9,Icefall Cave
|
||||
503,9,Patern Bush
|
||||
504,9,Lost Cave
|
||||
505,9,Kindle Road
|
||||
506,9,Treasure Beach
|
||||
507,9,Cape Brink
|
||||
508,9,Bond Bridge
|
||||
509,9,Three Isle Port
|
||||
510,9,Resort Gorgeous
|
||||
511,9,Water Labyrinth
|
||||
512,9,Five Isle Meadow
|
||||
513,9,Memorial Pillar
|
||||
514,9,Outcast Island
|
||||
515,9,Green Path
|
||||
516,9,Water Path
|
||||
517,9,Ruin Valley
|
||||
518,9,Trainer Tower
|
||||
519,9,Canyon Entrance
|
||||
520,9,Sevault Canyon
|
||||
521,9,Tanoby Ruins
|
||||
522,9,Route 19
|
||||
523,9,Route 20
|
||||
524,9,Route 21
|
||||
525,9,Vermillion City
|
||||
526,9,One Island
|
||||
527,9,Four Island
|
||||
528,9,Five Island
|
||||
529,9,Altering Cave
|
||||
530,9,Victory Road
|
||||
|
|
|
|
@ -331,3 +331,190 @@ id,region_id,identifier
|
|||
341,,concert-event
|
||||
342,,mr-pokemon
|
||||
343,,primo
|
||||
344,5,mystery-zone
|
||||
345,5,faraway-place
|
||||
346,5,nuvema-town
|
||||
347,5,accumula-town
|
||||
348,5,striaton-city
|
||||
349,5,nacrene-city
|
||||
350,5,castelia-city
|
||||
351,5,nimbasa-city
|
||||
352,5,driftveil-city
|
||||
353,5,mistralton-city
|
||||
354,5,icirrus-city
|
||||
355,5,opelucid-city
|
||||
356,5,route-1
|
||||
357,5,route-2
|
||||
358,5,route-3
|
||||
359,5,route-4
|
||||
360,5,route-5
|
||||
361,5,route-6
|
||||
362,5,route-7
|
||||
363,5,route-8
|
||||
364,5,route-9
|
||||
365,5,route-10
|
||||
366,5,route-11
|
||||
367,5,route-12
|
||||
368,5,route-13
|
||||
369,5,route-14
|
||||
370,5,route-15
|
||||
371,5,route-16
|
||||
372,5,route-17
|
||||
373,5,route-18
|
||||
374,5,dreamyard
|
||||
375,5,pinwheel-forest
|
||||
376,5,desert-resort
|
||||
377,5,relic-castle
|
||||
378,5,cold-storage
|
||||
379,5,chargestone-cave
|
||||
380,5,twist-mountain
|
||||
381,5,dragonspiral-tower
|
||||
382,5,victory-road
|
||||
383,5,lacunosa-town
|
||||
384,5,undella-town
|
||||
385,5,anville-town
|
||||
386,5,pokemon-league
|
||||
387,5,ns-castle
|
||||
388,5,royal-unova
|
||||
389,5,gear-station
|
||||
390,5,battle-subway
|
||||
391,5,musical-theater
|
||||
392,5,black-city
|
||||
393,5,white-forest
|
||||
394,5,unity-tower
|
||||
395,5,wellspring-cave
|
||||
396,5,mistralton-cave
|
||||
397,5,rumination-field
|
||||
398,5,celestial-tower
|
||||
399,5,moor-of-icirrus
|
||||
400,5,shopping-mall
|
||||
401,5,challengers-cave
|
||||
402,5,poke-transfer-lab
|
||||
403,5,giant-chasm
|
||||
404,5,liberty-garden
|
||||
405,5,p2-laboratory
|
||||
406,5,skyarrow-bridge
|
||||
407,5,driftveil-drawbridge
|
||||
408,5,tubeline-bridge
|
||||
409,5,village-bridge
|
||||
410,5,marvelous-bridge
|
||||
411,5,entralink
|
||||
412,5,abundant-shrine
|
||||
413,5,undella-bay
|
||||
414,5,lostlorn-forest
|
||||
415,5,trial-chamber
|
||||
416,5,guidance-chamber
|
||||
417,5,entree-forest
|
||||
418,5,accumula-gate
|
||||
419,5,undella-gate
|
||||
420,5,nacrene-gate
|
||||
421,5,castelia-gate
|
||||
422,5,nimbasa-gate
|
||||
423,5,opelucid-gate
|
||||
424,5,black-gate
|
||||
425,5,white-gate
|
||||
426,5,bridge-gate
|
||||
427,5,route-gate
|
||||
428,5,abyssal-ruins
|
||||
429,3,petalburg-city
|
||||
430,3,slateport-city
|
||||
431,3,lilycove-city
|
||||
432,3,mossdeep-city
|
||||
433,3,sootopolis-city
|
||||
434,3,ever-grande-city
|
||||
435,3,meteor-falls
|
||||
436,3,rusturf-tunnel
|
||||
437,3,granite-cave
|
||||
438,3,petalburg-woods
|
||||
439,3,jagged-pass
|
||||
440,3,fiery-pass
|
||||
441,3,mt-pyre
|
||||
442,3,seafloor-cavern
|
||||
443,3,cave-of-origin
|
||||
444,3,victory-road
|
||||
445,3,shoal-cave
|
||||
446,3,new-mauville
|
||||
447,3,abandoned-ship
|
||||
448,3,sky-pillar
|
||||
449,3,route-101
|
||||
450,3,route-102
|
||||
451,3,route-103
|
||||
452,3,route-104
|
||||
453,3,route-105
|
||||
454,3,route-106
|
||||
455,3,route-107
|
||||
456,3,route-108
|
||||
457,3,route-109
|
||||
458,3,route-110
|
||||
459,3,route-111
|
||||
460,3,route-112
|
||||
461,3,route-113
|
||||
462,3,route-114
|
||||
463,3,route-115
|
||||
464,3,route-116
|
||||
465,3,route-117
|
||||
466,3,route-118
|
||||
467,3,route-119
|
||||
468,3,route-120
|
||||
469,3,route-121
|
||||
470,3,route-122
|
||||
471,3,route-123
|
||||
472,3,route-124
|
||||
473,3,route-125
|
||||
474,3,route-126
|
||||
475,3,route-127
|
||||
476,3,route-128
|
||||
477,3,route-129
|
||||
478,3,route-130
|
||||
479,3,route-131
|
||||
480,3,route-132
|
||||
481,3,route-133
|
||||
482,3,route-134
|
||||
483,3,safari-zone
|
||||
484,3,dewford-town
|
||||
485,3,pacifidlog-town
|
||||
486,3,magma-hideout
|
||||
487,3,mirage-tower
|
||||
488,3,desert-underpass
|
||||
489,3,artisan-cave
|
||||
490,3,altering-cave
|
||||
491,1,monean-chamber
|
||||
492,1,liptoo-chamber
|
||||
493,1,weepth-chamber
|
||||
494,1,dilford-chamber
|
||||
495,1,scufib-chamber
|
||||
496,1,rixy-chamber
|
||||
497,1,viapos-chamber
|
||||
498,1,ss-anne
|
||||
499,1,victory-road
|
||||
500,1,mt-ember
|
||||
501,1,berry-forest
|
||||
502,1,icefall-cave
|
||||
503,1,patern-bush
|
||||
504,1,lost-cave
|
||||
505,1,kindle-road
|
||||
506,1,treasure-beach
|
||||
507,1,cape-brink
|
||||
508,1,bond-bridge
|
||||
509,1,three-isle-port
|
||||
510,1,resort-gorgeous
|
||||
511,1,water-labyrinth
|
||||
512,1,five-isle-meadow
|
||||
513,1,memorial-pillar
|
||||
514,1,outcast-island
|
||||
515,1,green-path
|
||||
516,1,water-path
|
||||
517,1,ruin-valley
|
||||
518,1,trainer-tower
|
||||
519,1,canyon-entrance
|
||||
520,1,sevault-canyon
|
||||
521,1,tanoby-ruins
|
||||
522,1,route-19
|
||||
523,1,route-20
|
||||
524,1,route-21
|
||||
525,1,vermillion-city
|
||||
526,1,one-island
|
||||
527,1,four-island
|
||||
528,1,five-island
|
||||
529,1,altering-cave
|
||||
530,1,victory-road
|
||||
|
|
|
|
@ -4,8 +4,8 @@ id,identifier
|
|||
3,tutor
|
||||
4,machine
|
||||
5,stadium-surfing-pikachu
|
||||
6,volt-tackle-pichu
|
||||
6,light-ball-egg
|
||||
7,colosseum-purification
|
||||
8,xd-shadow
|
||||
9,xd-purification
|
||||
10,rotom-form
|
||||
10,form-change
|
||||
|
|
|
|
@ -1,3 +1,6 @@
|
|||
# encoding: utf-8
|
||||
import re
|
||||
|
||||
from sqlalchemy import engine_from_config, orm
|
||||
|
||||
from ..defaults import get_default_db_uri
|
||||
|
@ -21,7 +24,7 @@ def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''):
|
|||
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:
|
||||
|
@ -51,3 +54,33 @@ def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''):
|
|||
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
|
||||
|
|
54
pokedex/db/dependencies.py
Normal file
54
pokedex/db/dependencies.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
import sqlalchemy.sql.visitors as visitors
|
||||
|
||||
from pokedex.db.tables import metadata
|
||||
|
||||
# stolen from sqlalchemy.sql.util.sort_tables
|
||||
def compute_dependencies(tables):
|
||||
"""Construct a reverse dependency graph for the given tables.
|
||||
|
||||
Returns a dict which maps a table to the list of tables which depend on it.
|
||||
"""
|
||||
tables = list(tables)
|
||||
graph = {}
|
||||
def visit_foreign_key(fkey):
|
||||
if fkey.use_alter:
|
||||
return
|
||||
parent_table = fkey.column.table
|
||||
if parent_table in tables:
|
||||
child_table = fkey.parent.table
|
||||
if parent_table is not child_table:
|
||||
graph.setdefault(parent_table, []).append(child_table)
|
||||
|
||||
for table in tables:
|
||||
visitors.traverse(table,
|
||||
{'schema_visitor': True},
|
||||
{'foreign_key': visit_foreign_key})
|
||||
|
||||
graph.setdefault(table, []).extend(table._extra_dependencies)
|
||||
|
||||
return graph
|
||||
|
||||
#: The dependency graph for pokedex.db.tables
|
||||
_pokedex_graph = compute_dependencies(metadata.tables.values())
|
||||
|
||||
def find_dependent_tables(tables, graph=None):
|
||||
"""Recursively find all tables which depend on the given tables.
|
||||
|
||||
The returned set does not include the original tables.
|
||||
"""
|
||||
if graph is None:
|
||||
graph = _pokedex_graph
|
||||
tables = list(tables)
|
||||
dependents = set()
|
||||
def add_dependents_of(table):
|
||||
for dependent_table in graph.get(table, []):
|
||||
if dependent_table not in dependents:
|
||||
dependents.add(dependent_table)
|
||||
add_dependents_of(dependent_table)
|
||||
|
||||
for table in tables:
|
||||
add_dependents_of(table)
|
||||
|
||||
dependents -= set(tables)
|
||||
|
||||
return dependents
|
|
@ -11,6 +11,7 @@ import sqlalchemy.types
|
|||
from pokedex.db import metadata
|
||||
import pokedex.db.tables as tables
|
||||
from pokedex.defaults import get_default_csv_dir
|
||||
from pokedex.db.dependencies import find_dependent_tables
|
||||
|
||||
|
||||
def _get_table_names(metadata, patterns):
|
||||
|
@ -52,7 +53,7 @@ def _get_verbose_prints(verbose):
|
|||
def print_start(thing):
|
||||
# Truncate to 66 characters, leaving 10 characters for a success
|
||||
# or failure message
|
||||
truncated_thing = thing[0:66]
|
||||
truncated_thing = thing[:66]
|
||||
|
||||
# Also, space-pad to keep the cursor in a known column
|
||||
num_spaces = 66 - len(truncated_thing)
|
||||
|
@ -95,7 +96,7 @@ def _get_verbose_prints(verbose):
|
|||
return print_start, print_status, print_done
|
||||
|
||||
|
||||
def load(session, tables=[], directory=None, drop_tables=False, verbose=False, safe=True):
|
||||
def load(session, tables=[], directory=None, drop_tables=False, verbose=False, safe=True, recursive=False):
|
||||
"""Load data from CSV files into the given database session.
|
||||
|
||||
Tables are created automatically.
|
||||
|
@ -119,6 +120,9 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
|
|||
`safe`
|
||||
If set to False, load can be faster, but can corrupt the database if
|
||||
it crashes or is interrupted.
|
||||
|
||||
`recursive`
|
||||
If set to True, load all dependent tables too.
|
||||
"""
|
||||
|
||||
# First take care of verbosity
|
||||
|
@ -128,8 +132,13 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
|
|||
if directory is None:
|
||||
directory = get_default_csv_dir()
|
||||
|
||||
# XXX why isn't this done in command_load
|
||||
table_names = _get_table_names(metadata, tables)
|
||||
table_objs = [metadata.tables[name] for name in table_names]
|
||||
|
||||
if recursive:
|
||||
table_objs.extend(find_dependent_tables(table_objs))
|
||||
|
||||
table_objs = sqlalchemy.sql.util.sort_tables(table_objs)
|
||||
|
||||
# SQLite speed tweaks
|
||||
|
@ -185,15 +194,15 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
|
|||
force_not_null = 'FORCE NOT NULL ' + ','.join('"%s"' % c for c in not_null_cols)
|
||||
else:
|
||||
force_not_null = ''
|
||||
command = "COPY {table_name} ({columns}) FROM '{csvpath}' CSV HEADER {force_not_null}"
|
||||
command = "COPY %(table_name)s (%(columns)s) FROM '%(csvpath)s' CSV HEADER %(force_not_null)s"
|
||||
session.connection().execute(
|
||||
command.format(
|
||||
table_name=table_name,
|
||||
csvpath=csvpath,
|
||||
columns=','.join('"%s"' % c for c in column_names),
|
||||
force_not_null=force_not_null,
|
||||
)
|
||||
command % dict(
|
||||
table_name=table_name,
|
||||
csvpath=csvpath,
|
||||
columns=','.join('"%s"' % c for c in column_names),
|
||||
force_not_null=force_not_null,
|
||||
)
|
||||
)
|
||||
session.commit()
|
||||
print_done()
|
||||
continue
|
||||
|
@ -203,12 +212,12 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
|
|||
# them to the session last
|
||||
# ASSUMPTION: Self-referential tables have a single PK called "id"
|
||||
deferred_rows = [] # ( row referring to id, [foreign ids we need] )
|
||||
seen_ids = {} # primary key we've seen => 1
|
||||
seen_ids = set() # primary keys we've seen
|
||||
|
||||
# Fetch foreign key columns that point at this table, if any
|
||||
self_ref_columns = []
|
||||
for column in table_obj.c:
|
||||
if any(_.references(table_obj) for _ in column.foreign_keys):
|
||||
if any(x.references(table_obj) for x in column.foreign_keys):
|
||||
self_ref_columns.append(column)
|
||||
|
||||
new_rows = []
|
||||
|
@ -247,18 +256,18 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
|
|||
# May need to stash this row and add it later if it refers to a
|
||||
# later row in this table
|
||||
if self_ref_columns:
|
||||
foreign_ids = [row_data[_.name] for _ in self_ref_columns]
|
||||
foreign_ids = [_ for _ in foreign_ids if _] # remove NULL ids
|
||||
foreign_ids = set(row_data[x.name] for x in self_ref_columns)
|
||||
foreign_ids.discard(None) # remove NULL ids
|
||||
|
||||
if not foreign_ids:
|
||||
# NULL key. Remember this row and add as usual.
|
||||
seen_ids[row_data['id']] = 1
|
||||
seen_ids.add(row_data['id'])
|
||||
|
||||
elif all(_ in seen_ids for _ in foreign_ids):
|
||||
elif foreign_ids.issubset(seen_ids):
|
||||
# Non-NULL key we've already seen. Remember it and commit
|
||||
# so we know the old row exists when we add the new one
|
||||
insert_and_commit()
|
||||
seen_ids[row_data['id']] = 1
|
||||
seen_ids.add(row_data['id'])
|
||||
|
||||
else:
|
||||
# Non-NULL future id. Save this and insert it later!
|
||||
|
@ -277,7 +286,7 @@ def load(session, tables=[], directory=None, drop_tables=False, verbose=False, s
|
|||
|
||||
# Attempt to add any spare rows we've collected
|
||||
for row_data, foreign_ids in deferred_rows:
|
||||
if not all(_ in seen_ids for _ in foreign_ids):
|
||||
if not foreign_ids.issubset(seen_ids):
|
||||
# Could happen if row A refers to B which refers to C.
|
||||
# This is ridiculous and doesn't happen in my data so far
|
||||
raise ValueError("Too many levels of self-reference! "
|
||||
|
|
|
@ -31,11 +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(
|
||||
|
|
|
@ -84,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 +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'))
|
||||
|
@ -134,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 +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 +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 +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 +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"))
|
||||
|
@ -246,7 +246,7 @@ 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'))
|
||||
|
@ -268,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 +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
|
||||
|
@ -304,14 +304,14 @@ class Encounter(TableBase):
|
|||
"""
|
||||
|
||||
__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 +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 +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 +364,46 @@ class EncounterConditionValueMap(TableBase):
|
|||
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 +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 +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 +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 +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 +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'))
|
||||
|
@ -519,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,7 +537,7 @@ 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'))
|
||||
|
@ -568,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 +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 +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 +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 +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 +656,8 @@ class LocationAreaEncounterRate(TableBase):
|
|||
__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 +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 +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 +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 +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,7 +780,7 @@ 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'))
|
||||
|
@ -798,7 +798,7 @@ 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',
|
||||
|
@ -813,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 +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,7 +873,7 @@ 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'))
|
||||
|
@ -895,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 +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,7 +975,7 @@ 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'))
|
||||
|
@ -993,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 +1026,9 @@ class NatureBattleStylePreference(TableBase):
|
|||
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 +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 +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 +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"))
|
||||
|
@ -1086,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'))
|
||||
|
@ -1153,7 +1153,7 @@ class Pokemon(TableBase):
|
|||
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
|
||||
|
||||
|
@ -1315,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 +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'))
|
||||
|
@ -1357,7 +1357,7 @@ class PokemonForm(TableBase):
|
|||
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
|
||||
|
||||
|
@ -1368,7 +1368,7 @@ class PokemonForm(TableBase):
|
|||
"""
|
||||
|
||||
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
|
||||
|
||||
|
@ -1495,7 +1495,7 @@ 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'))
|
||||
|
@ -1537,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 +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 +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 +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 +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 +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 +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."))
|
||||
|
@ -1674,9 +1674,9 @@ class VersionGroup(TableBase):
|
|||
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 +1747,7 @@ EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
|
|||
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 +1824,12 @@ LocationArea.location = relation(Location,
|
|||
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')
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
""" pokedex.defaults - logic for finding default paths """
|
||||
|
||||
import os
|
||||
import pkg_resources
|
||||
|
||||
def get_default_db_uri_with_origin():
|
||||
uri = os.environ.get('POKEDEX_DB_ENGINE', None)
|
||||
origin = 'environment'
|
||||
|
||||
if uri is None:
|
||||
import pkg_resources
|
||||
sqlite_path = pkg_resources.resource_filename('pokedex',
|
||||
'data/pokedex.sqlite')
|
||||
uri = 'sqlite:///' + sqlite_path
|
||||
|
@ -20,6 +20,7 @@ def get_default_index_dir_with_origin():
|
|||
origin = 'environment'
|
||||
|
||||
if index_dir is None:
|
||||
import pkg_resources
|
||||
index_dir = pkg_resources.resource_filename('pokedex',
|
||||
'data/whoosh-index')
|
||||
origin = 'default'
|
||||
|
@ -27,6 +28,7 @@ def get_default_index_dir_with_origin():
|
|||
return index_dir, origin
|
||||
|
||||
def get_default_csv_dir_with_origin():
|
||||
import pkg_resources
|
||||
csv_dir = pkg_resources.resource_filename('pokedex', 'data/csv')
|
||||
origin = 'default'
|
||||
|
||||
|
|
292
pokedex/main.py
Normal file
292
pokedex/main.py
Normal file
|
@ -0,0 +1,292 @@
|
|||
# encoding: utf8
|
||||
from optparse import OptionParser
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pokedex.db
|
||||
import pokedex.db.load
|
||||
import pokedex.db.tables
|
||||
import pokedex.lookup
|
||||
from pokedex import defaults
|
||||
|
||||
def main():
|
||||
if len(sys.argv) <= 1:
|
||||
command_help()
|
||||
|
||||
command = sys.argv[1]
|
||||
args = sys.argv[2:]
|
||||
|
||||
# XXX there must be a better way to get Unicode argv
|
||||
# XXX this doesn't work on Windows durp
|
||||
enc = sys.stdin.encoding or 'utf8'
|
||||
args = [_.decode(enc) for _ in args]
|
||||
|
||||
# Find the command as a function in this file
|
||||
func = globals().get("command_%s" % command, None)
|
||||
if func:
|
||||
func(*args)
|
||||
else:
|
||||
command_help()
|
||||
|
||||
|
||||
def get_parser(verbose=True):
|
||||
"""Returns an OptionParser prepopulated with the global options.
|
||||
|
||||
`verbose` is whether or not the options should be verbose by default.
|
||||
"""
|
||||
parser = OptionParser()
|
||||
parser.add_option('-e', '--engine', dest='engine_uri', default=None)
|
||||
parser.add_option('-i', '--index', dest='index_dir', default=None)
|
||||
parser.add_option('-q', '--quiet', dest='verbose', default=verbose, action='store_false')
|
||||
parser.add_option('-v', '--verbose', dest='verbose', default=verbose, action='store_true')
|
||||
return parser
|
||||
|
||||
def get_session(options):
|
||||
"""Given a parsed options object, connects to the database and returns a
|
||||
session.
|
||||
"""
|
||||
|
||||
engine_uri = options.engine_uri
|
||||
got_from = 'command line'
|
||||
|
||||
if engine_uri is None:
|
||||
engine_uri, got_from = defaults.get_default_db_uri_with_origin()
|
||||
|
||||
session = pokedex.db.connect(engine_uri)
|
||||
|
||||
if options.verbose:
|
||||
print "Connected to database %(engine)s (from %(got_from)s)" \
|
||||
% dict(engine=session.bind.url, got_from=got_from)
|
||||
|
||||
return session
|
||||
|
||||
def get_lookup(options, session=None, recreate=False):
|
||||
"""Given a parsed options object, opens the whoosh index and returns a
|
||||
PokedexLookup object.
|
||||
"""
|
||||
|
||||
if recreate and not session:
|
||||
raise ValueError("get_lookup() needs an explicit session to regen the index")
|
||||
|
||||
index_dir = options.index_dir
|
||||
got_from = 'command line'
|
||||
|
||||
if index_dir is None:
|
||||
index_dir, got_from = defaults.get_default_index_dir_with_origin()
|
||||
|
||||
if options.verbose:
|
||||
print "Opened lookup index %(index_dir)s (from %(got_from)s)" \
|
||||
% dict(index_dir=index_dir, got_from=got_from)
|
||||
|
||||
lookup = pokedex.lookup.PokedexLookup(index_dir, session=session)
|
||||
|
||||
if recreate:
|
||||
lookup.rebuild_index()
|
||||
|
||||
return lookup
|
||||
|
||||
def get_csv_directory(options):
|
||||
"""Prints and returns the csv directory we're about to use."""
|
||||
|
||||
if not options.verbose:
|
||||
return
|
||||
|
||||
csvdir = options.directory
|
||||
got_from = 'command line'
|
||||
|
||||
if csvdir is None:
|
||||
csvdir, got_from = defaults.get_default_csv_dir_with_origin()
|
||||
|
||||
print "Using CSV directory %(csvdir)s (from %(got_from)s)" \
|
||||
% dict(csvdir=csvdir, got_from=got_from)
|
||||
|
||||
return csvdir
|
||||
|
||||
|
||||
### Plumbing commands
|
||||
|
||||
def command_dump(*args):
|
||||
parser = get_parser(verbose=True)
|
||||
parser.add_option('-d', '--directory', dest='directory', default=None)
|
||||
options, tables = parser.parse_args(list(args))
|
||||
|
||||
session = get_session(options)
|
||||
get_csv_directory(options)
|
||||
|
||||
pokedex.db.load.dump(session, directory=options.directory,
|
||||
tables=tables,
|
||||
verbose=options.verbose)
|
||||
|
||||
def command_load(*args):
|
||||
parser = get_parser(verbose=True)
|
||||
parser.add_option('-d', '--directory', dest='directory', default=None)
|
||||
parser.add_option('-D', '--drop-tables', dest='drop_tables', default=False, action='store_true')
|
||||
parser.add_option('-r', '--recursive', dest='recursive', default=False, action='store_true')
|
||||
parser.add_option('-S', '--safe', dest='safe', default=False, action='store_true',
|
||||
help="Do not use backend-specific optimalizations.")
|
||||
options, tables = parser.parse_args(list(args))
|
||||
|
||||
if not options.engine_uri:
|
||||
print "WARNING: You're reloading the default database, but not the lookup index. They"
|
||||
print " might get out of sync, and pokedex commands may not work correctly!"
|
||||
print "To fix this, run `pokedex reindex` when this command finishes. Or, just use"
|
||||
print "`pokedex setup` to do both at once."
|
||||
print
|
||||
|
||||
session = get_session(options)
|
||||
get_csv_directory(options)
|
||||
|
||||
pokedex.db.load.load(session, directory=options.directory,
|
||||
drop_tables=options.drop_tables,
|
||||
tables=tables,
|
||||
verbose=options.verbose,
|
||||
safe=options.safe,
|
||||
recursive=options.recursive)
|
||||
|
||||
def command_reindex(*args):
|
||||
parser = get_parser(verbose=True)
|
||||
options, _ = parser.parse_args(list(args))
|
||||
|
||||
session = get_session(options)
|
||||
lookup = get_lookup(options, session=session, recreate=True)
|
||||
|
||||
print "Recreated lookup index."
|
||||
|
||||
|
||||
def command_setup(*args):
|
||||
parser = get_parser(verbose=False)
|
||||
options, _ = parser.parse_args(list(args))
|
||||
|
||||
options.directory = None
|
||||
|
||||
session = get_session(options)
|
||||
get_csv_directory(options)
|
||||
pokedex.db.load.load(session, directory=None, drop_tables=True,
|
||||
verbose=options.verbose,
|
||||
safe=False)
|
||||
|
||||
lookup = get_lookup(options, session=session, recreate=True)
|
||||
|
||||
print "Recreated lookup index."
|
||||
|
||||
|
||||
def command_status(*args):
|
||||
parser = get_parser(verbose=True)
|
||||
options, _ = parser.parse_args(list(args))
|
||||
options.verbose = True
|
||||
options.directory = None
|
||||
|
||||
# Database, and a lame check for whether it's been inited at least once
|
||||
session = get_session(options)
|
||||
print " - OK! Connected successfully."
|
||||
|
||||
if pokedex.db.tables.Pokemon.__table__.exists(session.bind):
|
||||
print " - OK! Database seems to contain some data."
|
||||
else:
|
||||
print " - WARNING: Database appears to be empty."
|
||||
|
||||
# CSV; simple checks that the dir exists
|
||||
csvdir = get_csv_directory(options)
|
||||
if not os.path.exists(csvdir):
|
||||
print " - ERROR: No such directory!"
|
||||
elif not os.path.isdir(csvdir):
|
||||
print " - ERROR: Not a directory!"
|
||||
else:
|
||||
print " - OK! Directory exists."
|
||||
|
||||
if os.access(csvdir, os.R_OK):
|
||||
print " - OK! Can read from directory."
|
||||
else:
|
||||
print " - ERROR: Can't read from directory!"
|
||||
|
||||
if os.access(csvdir, os.W_OK):
|
||||
print " - OK! Can write to directory."
|
||||
else:
|
||||
print " - WARNING: Can't write to directory! " \
|
||||
"`dump` will not work. You may need to sudo."
|
||||
|
||||
# Index; the PokedexLookup constructor covers most tests and will
|
||||
# cheerfully bomb if they fail
|
||||
lookup = get_lookup(options, recreate=False)
|
||||
print " - OK! Opened successfully."
|
||||
|
||||
|
||||
### User-facing commands
|
||||
|
||||
def command_lookup(*args):
|
||||
parser = get_parser(verbose=False)
|
||||
options, words = parser.parse_args(list(args))
|
||||
|
||||
name = u' '.join(words)
|
||||
|
||||
session = get_session(options)
|
||||
lookup = get_lookup(options, session=session, recreate=False)
|
||||
|
||||
results = lookup.lookup(name)
|
||||
if not results:
|
||||
print "No matches."
|
||||
elif results[0].exact:
|
||||
print "Matched:"
|
||||
else:
|
||||
print "Fuzzy-matched:"
|
||||
|
||||
for result in results:
|
||||
if hasattr(result.object, 'full_name'):
|
||||
name = result.object.full_name
|
||||
else:
|
||||
name = result.object.name
|
||||
|
||||
print "%s: %s" % (result.object.__tablename__, name),
|
||||
if result.language:
|
||||
print "(%s in %s)" % (result.name, result.language)
|
||||
else:
|
||||
print
|
||||
|
||||
|
||||
def command_help():
|
||||
print u"""pokedex -- a command-line Pokédex interface
|
||||
usage: pokedex {command} [options...]
|
||||
Run `pokedex setup` first, or nothing will work!
|
||||
See http://bugs.veekun.com/projects/pokedex/wiki/CLI for more documentation.
|
||||
|
||||
Commands:
|
||||
help Displays this message.
|
||||
lookup [thing] Look up something in the Pokédex.
|
||||
|
||||
System commands:
|
||||
load Load Pokédex data into a database from CSV files.
|
||||
dump Dump Pokédex data from a database into CSV files.
|
||||
reindex Rebuilds the lookup index from the database.
|
||||
setup Combines load and reindex.
|
||||
status No effect, but prints which engine, index, and csv
|
||||
directory would be used for other commands.
|
||||
|
||||
Global options:
|
||||
-e|--engine=URI By default, all commands try to use a SQLite database
|
||||
in the pokedex install directory. Use this option (or
|
||||
a POKEDEX_DB_ENGINE environment variable) to specify an
|
||||
alternate database.
|
||||
-i|--index=DIR By default, all commands try to put the lookup index in
|
||||
the pokedex install directory. Use this option (or a
|
||||
POKEDEX_INDEX_DIR environment variable) to specify an
|
||||
alternate loction.
|
||||
-q|--quiet Don't print system output. This is the default for
|
||||
non-system commands and setup.
|
||||
-v|--verbose Print system output. This is the default for system
|
||||
commands, except setup.
|
||||
|
||||
System options:
|
||||
-d|--directory=DIR By default, load and dump will use the CSV files in the
|
||||
pokedex install directory. Use this option to specify
|
||||
a different directory.
|
||||
|
||||
Load options:
|
||||
-D|--drop-tables Drop all tables before loading data.
|
||||
-S|--safe Disable engine-specific optimizations.
|
||||
-r|--recursive Load (and drop) all dependent tables.
|
||||
|
||||
Additionally, load and dump accept a list of table names (possibly with
|
||||
wildcards) and/or csv fileames as an argument list.
|
||||
""".encode(sys.getdefaultencoding(), 'replace')
|
||||
|
||||
sys.exit(0)
|
|
@ -145,4 +145,3 @@ except ImportError:
|
|||
pass
|
||||
|
||||
return result
|
||||
|
||||
|
|
49
scripts/add-bw-locations.py
Executable file
49
scripts/add-bw-locations.py
Executable file
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
from codecs import open
|
||||
|
||||
from pokedex.db import connect, identifier_from_name
|
||||
from pokedex.db.tables import Language
|
||||
from pokedex.db.tables import Location, LocationGameIndex
|
||||
|
||||
session = connect()
|
||||
|
||||
en = session.query(Language).filter_by(identifier='en').one() # English
|
||||
ja = session.query(Language).filter_by(identifier='ja').one() # Japanese
|
||||
|
||||
with open("bw-location-names-en", "r", "utf-8") as f:
|
||||
en_names = [line.rstrip("\n") for line in f]
|
||||
with open("bw-location-names-kanji", "r", "utf-8") as f:
|
||||
ja_names = [line.rstrip("\n") for line in f]
|
||||
|
||||
locations = {}
|
||||
for i, name in enumerate(zip(en_names, ja_names)):
|
||||
if i == 0:
|
||||
continue
|
||||
|
||||
en_name, ja_name = name
|
||||
if not en_name:
|
||||
continue
|
||||
|
||||
if name in locations:
|
||||
loc = locations[name]
|
||||
else:
|
||||
loc = Location()
|
||||
if en_name:
|
||||
loc.name_map[en] = en_name
|
||||
if ja_name:
|
||||
loc.name_map[ja] = ja_name
|
||||
loc.region_id = 5 # Unova
|
||||
loc.identifier = identifier_from_name(en_name)
|
||||
|
||||
locations[name] = loc
|
||||
|
||||
lgi = LocationGameIndex()
|
||||
lgi.location = loc
|
||||
lgi.generation_id = 5 # Gen 5
|
||||
lgi.game_index = i
|
||||
|
||||
session.add(loc)
|
||||
session.add(lgi)
|
||||
|
||||
session.commit()
|
272
scripts/migration-i18n.py
Normal file
272
scripts/migration-i18n.py
Normal file
|
@ -0,0 +1,272 @@
|
|||
# Encoding: UTF-8
|
||||
|
||||
"""Moves/transforms values in CSVs in an ad-hoc way, based mainly on column name
|
||||
|
||||
Auto-creates identifiers from names
|
||||
Auto-creates names from identifiers
|
||||
Copies IDs for foreign keys
|
||||
Creates autoincrement-style IDs when missing
|
||||
Sets text language to 9 (en), except when it sets to 1 (jp)
|
||||
|
||||
And looks good doing it!
|
||||
"""
|
||||
|
||||
import csv
|
||||
import re
|
||||
import os
|
||||
from StringIO import StringIO
|
||||
from collections import namedtuple, defaultdict
|
||||
|
||||
from sqlalchemy.orm import class_mapper
|
||||
|
||||
from pokedex.db import tables, load
|
||||
|
||||
english_id = 9
|
||||
japanese_id = 1
|
||||
|
||||
bw_version_group_id = 11
|
||||
|
||||
dir = load.get_default_csv_dir()
|
||||
|
||||
def tuple_key(tup):
|
||||
"""Return a sort key for mixed int/string tuples.
|
||||
|
||||
Strings sort first.
|
||||
"""
|
||||
def generator():
|
||||
for item in tup:
|
||||
try:
|
||||
yield (1, int(item))
|
||||
except ValueError:
|
||||
yield (0, item)
|
||||
return tuple(generator())
|
||||
|
||||
class MakeFieldFuncs:
|
||||
"""Various ways to get a new value from the old one"""
|
||||
@staticmethod
|
||||
def copy(field_name, source, **kwargs):
|
||||
"""Plain copy"""
|
||||
return source[field_name]
|
||||
|
||||
@staticmethod
|
||||
def main(field_name, source, **kwargs):
|
||||
"""Populate aux table from the main table"""
|
||||
return source[field_name]
|
||||
|
||||
@staticmethod
|
||||
def Main(field_name, source, **kwargs):
|
||||
"""Capitalize"""
|
||||
return source[field_name].capitalize()
|
||||
|
||||
@staticmethod
|
||||
def ident(source, **kwargs):
|
||||
"""Craft an identifier from the 'identifier' or 'name' column"""
|
||||
return name2ident(source.get('identifier', source.get('name')))
|
||||
|
||||
@staticmethod
|
||||
def Name(source, **kwargs):
|
||||
"""Capitalize the name (or identifier) column"""
|
||||
name = source.get('name', source.get('identifier', None))
|
||||
name = ' '.join(word.capitalize() for word in name.split(' '))
|
||||
return name
|
||||
|
||||
@staticmethod
|
||||
def f_id(source, **kwargs):
|
||||
"""Capitalize the identifier column"""
|
||||
return source['identifier'].capitalize()
|
||||
|
||||
@staticmethod
|
||||
def name(source, **kwargs):
|
||||
"""Get the original name"""
|
||||
return source['name']
|
||||
|
||||
@staticmethod
|
||||
def newid(i, source, **kwargs):
|
||||
"""Assign a new "auto-incremented" id"""
|
||||
source['id'] = i # hack to make srcid work
|
||||
return i
|
||||
|
||||
@staticmethod
|
||||
def en(source, **kwargs):
|
||||
"""Assign the value for English -- unless it's Japanese"""
|
||||
if source.get('version_group_id', None) == str(bw_version_group_id):
|
||||
return japanese_id
|
||||
return english_id
|
||||
|
||||
@staticmethod
|
||||
def srcid(source, field_name, **kwargs):
|
||||
"""The original table's id"""
|
||||
try:
|
||||
return source['id']
|
||||
except KeyError:
|
||||
if field_name == 'pokemon_form_group_id':
|
||||
# This one reuses another table's ID
|
||||
return source['pokemon_id']
|
||||
else:
|
||||
raise
|
||||
|
||||
def name2ident(name):
|
||||
ident = name.decode('utf-8').lower()
|
||||
ident = ident.replace(u'+', ' plus ')
|
||||
ident = re.sub(u'[ _–]+', u'-', ident)
|
||||
ident = re.sub(u'[\'./;’(),:]', u'', ident)
|
||||
ident = ident.replace(u'é', 'e')
|
||||
ident = ident.replace(u'♀', '-f')
|
||||
ident = ident.replace(u'♂', '-m')
|
||||
if ident in ('???', '????'):
|
||||
ident = 'unknown'
|
||||
elif ident == '!':
|
||||
ident = 'exclamation'
|
||||
elif ident == '?':
|
||||
ident = 'question'
|
||||
for c in ident:
|
||||
assert c in "abcdefghijklmnopqrstuvwxyz0123456789-", repr(ident)
|
||||
return ident
|
||||
|
||||
|
||||
FieldSpec = namedtuple('FieldSpec', 'out name func')
|
||||
|
||||
def main():
|
||||
for table in sorted(tables.all_tables(), key=lambda t: t.__name__):
|
||||
datafilename = dir + '/' + table.__tablename__ + '.csv'
|
||||
classname = table.__name__
|
||||
if hasattr(table, 'object_table'):
|
||||
# This is an auxilliary table; it'll be processed with the main one
|
||||
continue
|
||||
else:
|
||||
print "%s: %s" % (classname, table.__tablename__)
|
||||
with open(datafilename) as datafile:
|
||||
datacsv = csv.reader(datafile, lineterminator='\n')
|
||||
orig_fields = datacsv.next()
|
||||
columns = class_mapper(table).c
|
||||
new_fields = []
|
||||
main_out = []
|
||||
outputs = {datafilename: main_out}
|
||||
name_out = None
|
||||
srcfiles = [datafilename]
|
||||
# Set new_fields to a list of FieldSpec object, one for each field we want in the csv
|
||||
for column in columns:
|
||||
name = column.name
|
||||
if name == 'identifier':
|
||||
new_fields.append(FieldSpec(datafilename, column.name, MakeFieldFuncs.ident))
|
||||
elif name in orig_fields:
|
||||
new_fields.append(FieldSpec(datafilename, column.name, MakeFieldFuncs.copy))
|
||||
elif name == 'id':
|
||||
new_fields.append(FieldSpec(datafilename, column.name, MakeFieldFuncs.newid))
|
||||
elif name == 'language_id':
|
||||
new_fields.insert(2, FieldSpec(datafilename, column.name, MakeFieldFuncs.en))
|
||||
else:
|
||||
raise AssertionError(name)
|
||||
# Remember headers
|
||||
headers = {datafilename: list(field.name for field in new_fields)}
|
||||
# Pretty prnt :)
|
||||
for field in new_fields:
|
||||
print ' [{0.func.func_name:5}] {0.name}'.format(field)
|
||||
# Do pretty much the same for aux tables
|
||||
aux_tables = []
|
||||
for attrname in 'text_table prose_table'.split():
|
||||
aux_table = getattr(table, attrname, None)
|
||||
if aux_table:
|
||||
aux_datafilename = dir + '/' + aux_table.__tablename__ + '.csv'
|
||||
print " %s: %s" % (aux_table.__name__, aux_table.__tablename__)
|
||||
srcfiles.append(datafilename)
|
||||
aux_tables.append(aux_table)
|
||||
columns = class_mapper(aux_table).c
|
||||
aux_out = []
|
||||
outputs[aux_datafilename] = aux_out
|
||||
aux_fields = []
|
||||
for column in columns:
|
||||
name = column.name
|
||||
if name == 'language_id':
|
||||
aux_fields.insert(1, FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.en))
|
||||
elif name == 'name' and table.__name__ == 'ItemFlag':
|
||||
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.f_id))
|
||||
elif name == 'description' and table.__name__ == 'ItemFlag':
|
||||
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.name))
|
||||
elif name in orig_fields and name == 'name' and table.__name__ in 'PokemonColor ContestType BerryFirmness'.split():
|
||||
# Capitalize these names
|
||||
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.Name))
|
||||
elif name in orig_fields and name in 'color flavor'.split() and table.__name__ == 'ContestType':
|
||||
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.Main))
|
||||
elif name in orig_fields:
|
||||
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.main))
|
||||
elif name == table.__singlename__ + '_id':
|
||||
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.srcid))
|
||||
elif name == 'name':
|
||||
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.Name))
|
||||
elif name == 'lang_id':
|
||||
aux_fields.append(FieldSpec(aux_datafilename, column.name, MakeFieldFuncs.srcid))
|
||||
else:
|
||||
print orig_fields
|
||||
raise AssertionError(name)
|
||||
if name == 'name':
|
||||
# If this table contains the name, remember that
|
||||
name_fields = aux_fields
|
||||
name_out = aux_out
|
||||
# Sort aux tables nicely
|
||||
def key(f):
|
||||
if f.func == MakeFieldFuncs.srcid:
|
||||
return 0
|
||||
elif f.name == 'language_id':
|
||||
return 1
|
||||
elif f.name == 'name':
|
||||
return 2
|
||||
else:
|
||||
return 10
|
||||
aux_fields.sort(key=key)
|
||||
new_fields += aux_fields
|
||||
headers[aux_datafilename] = list(field.name for field in aux_fields)
|
||||
# Pretty print :)
|
||||
for field in aux_fields:
|
||||
print ' [{0.func.func_name:5}] {0.name}'.format(field)
|
||||
# Do nothing if the table's the same
|
||||
if all(field.func == MakeFieldFuncs.copy for field in new_fields):
|
||||
print u' → skipping'
|
||||
continue
|
||||
# Otherwise read the file
|
||||
# outputs will be a (filename -> list of rows) dict
|
||||
print u' → reading'
|
||||
for autoincrement_id, src_row in enumerate(datacsv, start=1):
|
||||
row = dict(zip(orig_fields, src_row))
|
||||
new_rows = defaultdict(list)
|
||||
for field in new_fields:
|
||||
new_rows[field.out].append(field.func(
|
||||
source=row,
|
||||
field_name=field.name,
|
||||
i=autoincrement_id,
|
||||
))
|
||||
for name, row in new_rows.items():
|
||||
outputs[name].append(row)
|
||||
# If there was a _names table, read that and append it to the
|
||||
# aux table that has names
|
||||
try:
|
||||
name_datafilename = dir + '/' + table.__singlename__ + '_names.csv'
|
||||
name_file = open(name_datafilename)
|
||||
except (AttributeError, IOError):
|
||||
pass
|
||||
else:
|
||||
print u' → reading foreign names'
|
||||
with name_file:
|
||||
namecsv = csv.reader(name_file, lineterminator='\n')
|
||||
src_fields = namecsv.next()
|
||||
obj_id_fieldname = table.__singlename__ + '_id'
|
||||
assert src_fields == [obj_id_fieldname, 'language_id', 'name']
|
||||
for name_row in namecsv:
|
||||
name_dict = dict(zip(src_fields, name_row))
|
||||
row = []
|
||||
for field in name_fields:
|
||||
row.append(name_dict.get(field.name, ''))
|
||||
name_out.append(row)
|
||||
os.unlink(name_datafilename)
|
||||
# For all out files, write a header & sorted rows
|
||||
print u' → writing'
|
||||
for filename, rows in outputs.items():
|
||||
with open(filename, 'w') as outfile:
|
||||
outcsv = csv.writer(outfile, lineterminator='\n')
|
||||
outcsv.writerow(headers[filename])
|
||||
rows.sort(key=tuple_key)
|
||||
for row in rows:
|
||||
outcsv.writerow(row)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
2
setup.py
2
setup.py
|
@ -16,7 +16,7 @@ setup(
|
|||
|
||||
entry_points = {
|
||||
'console_scripts': [
|
||||
'pokedex = pokedex:main',
|
||||
'pokedex = pokedex.main:main',
|
||||
],
|
||||
},
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue