static void Main(string[] args) { string veekunFilename; ConnectionStringSettings css; if (args.Length < 1) { veekunFilename = "pokedex.sqlite"; } else { veekunFilename = args[0]; } if (veekunFilename.Contains(';')) { throw new NotSupportedException("The character ; in filenames is not supported."); } if (veekunFilename.Contains('?')) { Console.WriteLine("Usage: VeekunImport [filename [connectionString providerName]]"); Console.WriteLine("filename: Filename of Veekun sqlite database. Default: pokedex.sqlite"); Console.WriteLine("connectionString: pkmnFoundations connection string. Default: from app.config"); Console.WriteLine("providerName: .NET classname of connection provider. Default: from app.config"); return; } if (args.Length < 3) { css = ConfigurationManager.ConnectionStrings["pkmnFoundationsConnectionString"]; } else { css = new ConnectionStringSettings("", args[1], args[2]); } Database db = Database.CreateInstance(css); using (SQLiteConnection connVeekun = new SQLiteConnection("Data Source=" + veekunFilename + "; Version=3")) { connVeekun.Open(); // General logic: // 1. run a query against veekun, populate a DataTable. // 2. foreach DataRow, instance a class from the PkmnFoundations.Pokedex namespace. // 3. call Database.AddToPokedex on that object. // todo: We need a way to rebuild specific tables // pkmncf_pokedex_pokemon_families // Obtain the families map. We will use it in a few places. Dictionary <int, int> familyMap = new Dictionary <int, int>(); List <int[]> familyList = new List <int[]>(); ProcessTSV("families_map.txt", 1, row => { // todo: allow for comments by stopping consumption of fields once one fails to parse. int[] fieldsInt = row.Fields.Select(s => Convert.ToInt32(s)).ToArray(); familyList.Add(fieldsInt); foreach (int x in fieldsInt) { // lineNumber is one-based, unlike familyList index. // species is the key, family ID is the value. // If any species is repeated in family_map.txt, this ought to fail. familyMap.Add(x, row.ValidLineNumber + 1); } }); // families from families.txt override default behaviour. List <Family> overrideFamilies = new List <Family>(); ProcessTSV("families.txt", 7, row => { string[] fields = row.Fields; overrideFamilies.Add(new Family(null, Convert.ToInt32(fields[0]), Convert.ToInt32(fields[1]), Convert.ToInt32(fields[2]), Convert.ToInt32(fields[3]), Convert.ToInt32(fields[4]), Convert.ToInt32(fields[5]), Convert.ToByte(fields[6]) )); }); // already sorted //someFamilies.Sort((f, other) => f.ID.CompareTo(other.ID)); int familyCount = familyList.Count; int nextOverrideIndex = 0; for (int familyId = 1; familyId <= familyCount; familyId++) { int basicSpeciesId = familyList[familyId - 1][0]; Family f; if (nextOverrideIndex < overrideFamilies.Count && overrideFamilies[nextOverrideIndex].ID == familyId) { // An override exists in the table; use it. f = overrideFamilies[nextOverrideIndex]; nextOverrideIndex++; } else { // No override exists so go with default: // Basic male/female are the same species which is the one listed first. // There is no baby species nor incense // (Non-incense babies are considered basic in this system anyway.) // Gender ratio comes from the basic species. byte genderRatio = (byte)Convert.ToInt32(connVeekun.ExecuteScalar("SELECT gender_rate FROM pokemon_species WHERE id = @id", new SQLiteParameter("@id", basicSpeciesId))); f = new Family(null, familyId, basicSpeciesId, basicSpeciesId, 0, 0, 0, genderRatio); } db.PokedexInsertFamily(f); string basic = (f.BasicMaleID != f.BasicFemaleID) ? String.Format(" {0}/{1}", f.BasicMaleID, f.BasicFemaleID) : String.Format(" {0}", f.BasicMaleID); string baby; if (f.BabyMaleID != f.BabyFemaleID) { baby = String.Format(" {0}/{1} incense {2}", f.BabyMaleID, f.BabyFemaleID, f.IncenseID); } else { baby = (f.BabyMaleID == 0) ? "" : String.Format(" {0} incense {1}", f.BabyMaleID, f.IncenseID); } string gender = (f.GenderRatio == 255) ? "genderless" : String.Format("{0}% female", (float)f.GenderRatio * 12.5f); Console.WriteLine("Inserted family {0}{1}{2} {3}", f.ID, basic, baby, gender); } // pkmncf_pokedex_pokemon SQLiteDataReader rdPokemon = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT " + "pokemon_species.id, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 1) AS name_ja, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 9) AS name_en, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 5) AS name_fr, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 8) AS name_it, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 6) AS name_de, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 7) AS name_es, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 3) AS name_ko, " + "growth_rate_id, gender_rate, " + "(SELECT egg_group_id FROM pokemon_egg_groups WHERE species_id = pokemon_species.id ORDER BY egg_group_id LIMIT 1) AS egg_group_1, " + "(SELECT egg_group_id FROM pokemon_egg_groups WHERE species_id = pokemon_species.id ORDER BY egg_group_id LIMIT 1, 1) AS egg_group_2, " + "hatch_counter, has_gender_differences " + "FROM pokemon_species " + "ORDER BY pokemon_species.id"); while (rdPokemon.Read()) { int id = Convert.ToInt32(rdPokemon["id"]); byte growth_rate_id = Convert.ToByte(rdPokemon["growth_rate_id"]); int gender_rate = Convert.ToInt32(rdPokemon["gender_rate"]); byte egg_group_1 = Convert.ToByte(rdPokemon["egg_group_1"]); byte egg_group_2 = 0; if (!(rdPokemon["egg_group_2"] is DBNull)) { egg_group_2 = Convert.ToByte(rdPokemon["egg_group_2"]); } int hatch_counter = Convert.ToInt32(rdPokemon["hatch_counter"]); byte has_gender_differences = Convert.ToByte(rdPokemon["has_gender_differences"]); if (id == 255) { has_gender_differences = 0; // Torchic doesn't have gender differences. } // todo: Family ID Species s = new Species(null, id, familyMap[id], GetLocalizedString(rdPokemon, "name_"), (GrowthRates)growth_rate_id, (byte)gender_rate, (EggGroups)egg_group_1, (EggGroups)egg_group_2, (byte)hatch_counter, has_gender_differences != 0 ); db.PokedexInsertSpecies(s); Console.WriteLine("Inserted {0} {1} {2} {3} {4} {5}", s.NationalDex, s.Name.ToString(), s.GrowthRate, s.GenderRatio, s.EggSteps, s.GenderVariations); } rdPokemon.Close(); // pkmncf_pokedex_pokemon_forms Dictionary <int, byte> formValueMap = new Dictionary <int, byte>(); ProcessTSV("form_values.txt", 3, row => { string[] fields = row.Fields; formValueMap.Add(Convert.ToInt32(fields[1]), Convert.ToByte(fields[2])); }); SQLiteDataReader rdForms = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, " + "(SELECT species_id FROM pokemon WHERE id = pokemon_id) AS NationalDex, " + "form_order - 1 AS FormValue, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 1) AS name_ja, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 9) AS name_en, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 5) AS name_fr, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 8) AS name_it, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 6) AS name_de, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 7) AS name_es, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 3) AS name_ko, " + "form_identifier, " + "(SELECT height FROM pokemon WHERE id = pokemon_id) AS height, " + "(SELECT weight FROM pokemon WHERE id = pokemon_id) AS weight, " + "(SELECT base_experience FROM pokemon WHERE id = pokemon_id) AS experience " + "FROM pokemon_forms"); while (rdForms.Read()) { int id = Convert.ToInt32(rdForms["id"]); int NationalDex = Convert.ToInt32(rdForms["NationalDex"]); byte FormValue = Convert.ToByte(rdForms["FormValue"]); string form_identifier = rdForms["form_identifier"].ToString(); int height = Convert.ToInt32(rdForms["height"]); int weight = Convert.ToInt32(rdForms["weight"]); int experience = Convert.ToInt32(rdForms["experience"]); if (formValueMap.ContainsKey(id)) { FormValue = formValueMap[id]; } Form f = new Form(null, id, NationalDex, FormValue, GetLocalizedString(rdForms, "name_"), form_identifier, height, weight, experience ); db.PokedexInsertForm(f); Console.WriteLine("Inserted {0} {1} {2} {3} {4} {5:0.0}m {6:0.0}kg {7}", f.ID, f.SpeciesID, f.Value, f.Name.ToString(), f.Suffix, f.Height * 0.1f, f.Weight * 0.1f, f.Experience); } rdForms.Close(); // pkmncf_pokedex_pokemon_form_stats for (int generation = 1; generation <= GENERATIONS; generation++) { string filename = String.Format("form_stats{0}.txt", generation); ProcessTSV(filename, 15, row => { int[] fieldsInt = row.Fields.Select(s => Convert.ToInt32(s)).ToArray(); FormStats f = new FormStats(null, fieldsInt[0], (Generations)generation, fieldsInt[1], fieldsInt[2], new IntStatValues(fieldsInt[3], fieldsInt[4], fieldsInt[5], fieldsInt[6], fieldsInt[7], fieldsInt[8]), new ByteStatValues((byte)fieldsInt[9], (byte)fieldsInt[10], (byte)fieldsInt[11], (byte)fieldsInt[12], (byte)fieldsInt[13], (byte)fieldsInt[14]) ); db.PokedexInsertFormStats(f); Console.WriteLine("Inserted stats for {0} gen {1}", f.FormID, (int)f.MinGeneration); }); } // todo: pkmncf_pokedex_pokemon_evolutions // pkmncf_pokedex_types SQLiteDataReader rdTypes = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, damage_class_id, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 3) AS name_ko " + "FROM types ORDER BY id"); // http://stackoverflow.com/questions/27156585/failed-to-enable-constraints-without-dataadapter while (rdTypes.Read()) { int id = Convert.ToInt32(rdTypes["id"]); PkmnFoundations.Pokedex.Type t = new PkmnFoundations.Pokedex.Type(null, id, GetLocalizedString(rdTypes, "name_"), GetDamageClass(rdTypes)); db.PokedexInsertType(t); Console.WriteLine("Inserted type {0} {1} {2}", t.ID, t.Name.ToString(), t.DamageClass); } rdTypes.Close(); // pkmncf_pokedex_moves SQLiteDataReader rdMoves = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, type_id, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 3) AS name_ko, " + "damage_class_id, power, pp, accuracy, priority, target_id FROM moves"); while (rdMoves.Read()) { int id = Convert.ToInt32(rdMoves["id"]); int type_id = Convert.ToInt32(rdMoves["type_id"]); int damage_class_id = Convert.ToInt32(rdMoves["damage_class_id"]); short power = DatabaseExtender.Cast <short?>(rdMoves["power"]) ?? 0; short pp = DatabaseExtender.Cast <short?>(rdMoves["pp"]) ?? 0; short accuracy = DatabaseExtender.Cast <short?>(rdMoves["accuracy"]) ?? 0; short priority = Convert.ToInt16(rdMoves["priority"]); int target_id = Convert.ToInt32(rdMoves["target_id"]); Move m = new Move(null, id, type_id, GetLocalizedString(rdMoves, "name_"), (DamageClass)damage_class_id, power, pp, accuracy, priority, (BattleTargets)target_id ); db.PokedexInsertMove(m); Console.WriteLine("Inserted move {0} {1}", m.ID, m.Name.ToString()); } // pkmncf_pokedex_abilities SQLiteDataReader rdAbilities = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 3) AS name_ko " + "FROM abilities WHERE is_main_series = 1"); while (rdAbilities.Read()) { int id = Convert.ToInt32(rdAbilities["id"]); Ability a = new Ability(null, id, GetLocalizedString(rdAbilities, "name_") ); db.PokedexInsertAbility(a); Console.WriteLine("Inserted ability {0} {1}", a.Value, a.Name.ToString()); } rdAbilities.Close(); // pkmncf_pokedex_items Dictionary <int, ItemLoading> items = new Dictionary <int, ItemLoading>(); for (int generation = 3; generation <= GENERATIONS; generation++) { string filename = String.Format("items{0}.txt", generation); ProcessTSV(filename, 3, row => { string[] fields = row.Fields; int id, thisGenId; string name = fields[1]; if (!Int32.TryParse(fields[0], out thisGenId) || !Int32.TryParse(fields[2], out id)) { Console.WriteLine("{0} line {1} has bad format, skipped.", filename, row.LineNumber); return; } ItemLoading theItem = null; if (!items.ContainsKey(id)) { theItem = new ItemLoading(id, name); items.Add(id, theItem); } theItem = theItem ?? items[id]; theItem.Name = name; // prefer newer names where available theItem.SetGenerationValue(thisGenId, generation); }); } // Pokeball IDs: ProcessTSV("items_balls.txt", 3, row => { string[] fields = row.Fields; int id, ballId; string name = fields[1]; if (!Int32.TryParse(fields[0], out ballId) || !Int32.TryParse(fields[2], out id)) { Console.WriteLine("{0} line {1} has bad format, skipped.", "items_balls.txt", row.LineNumber); return; } ItemLoading theItem = null; if (!items.ContainsKey(id)) { theItem = new ItemLoading(id, name); items.Add(id, theItem); } theItem = theItem ?? items[id]; if (theItem.Name == null) { theItem.Name = name; } theItem.PokeballValue = ballId; }); // lookup Veekun ID number against some generation or another. Dictionary <int, ItemLoading> items3 = items .Where(i => i.Value.Value3 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value3, i => i.Value); Dictionary <int, ItemLoading> items4 = items .Where(i => i.Value.Value4 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value4, i => i.Value); Dictionary <int, ItemLoading> items5 = items .Where(i => i.Value.Value5 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value5, i => i.Value); Dictionary <int, ItemLoading> items6 = items .Where(i => i.Value.Value6 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value6, i => i.Value); // veekun has incorrect Gen3 indices for Helix/Dome fossil. // (Or they disagree with Bulbapedia which is my primary source) SQLiteDataReader rdItems = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, cost, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 3 AND NOT item_id IN (101, 102)) AS value3, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 4) AS value4, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 5) AS value5, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 6) AS value6, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 3) AS name_ko " + "FROM items"); Dictionary <int, ItemLoading>[] itemsGeneration = new Dictionary <int, ItemLoading>[] { null, null, items3, items4, items5, items6 }; while (rdItems.Read()) { List <ItemLoading> toProcess = new List <ItemLoading>(4); for (int generation = 3; generation <= GENERATIONS; generation++) { string col = String.Format("value{0}", generation); if (!(rdItems[col] is DBNull)) { Dictionary <int, ItemLoading> dict = itemsGeneration[generation - 1]; int value = Convert.ToInt32(rdItems[col]); if (dict.ContainsKey(value)) { ItemLoading il = dict[value]; il.NameLocalized = GetLocalizedString(rdItems, "name_"); il.Price = Convert.ToInt32(rdItems["cost"]); } } } } rdItems.Close(); foreach (ItemLoading il in items.Values) { LocalizedString name = il.NameLocalized; if (name == null) { name = new LocalizedString() { { "EN", il.Name } }; Console.WriteLine("Veekun database missing item {0} {1}. Non-English translations will be missing.", il.ID, name); } Item i = new Item(null, il.ID, il.Value3, il.Value4, il.Value5, il.Value6, il.PokeballValue, il.Price, name); db.PokedexInsertItem(i); Console.WriteLine("Inserted item {0} {1}", i.ID, i.Name.ToString()); } // pkmncf_pokedex_ribbons Dictionary <int, RibbonLoading> ribbons = new Dictionary <int, RibbonLoading>(); if (!ProcessTSV("ribbons.txt", 3, row => { string[] fields = row.Fields; int id = Convert.ToInt32(fields[0]); ribbons.Add(id, new RibbonLoading(id, fields[1], fields[2])); })) { Console.WriteLine("ribbons.txt not found. Not inserting any ribbons."); } else { for (int generation = 3; generation <= GENERATIONS; generation++) { string filename = String.Format("ribbon_positions{0}.txt", generation); ProcessTSV(filename, 2, row => { string[] fields = row.Fields; int id = Convert.ToInt32(fields[0]); int position = Convert.ToInt32(fields[1]); if (!ribbons.ContainsKey(id)) { Console.WriteLine("Error: Ribbon ID {0} contained in {1} but not in ribbons.txt!", id, filename); return; } RibbonLoading r = ribbons[id]; r.SetGenerationPosition(position, generation); }); } foreach (KeyValuePair <int, RibbonLoading> pair in ribbons) { RibbonLoading r = pair.Value; db.PokedexInsertRibbon(new Ribbon(null, r.ID, new LocalizedString() { { "EN", r.Name } }, new LocalizedString() { { "EN", r.Description } }, r.Position3, r.Position4, r.Position5, r.Position6, null, null, null, null )); Console.WriteLine("Inserted ribbon {0} {1}", r.ID, r.Name); } } // pkmncf_pokedex_regions ProcessTSV("regions.txt", 2, row => { string[] fields = row.Fields; int id = Convert.ToInt32(fields[0]); Region r = new Region(null, id, new LocalizedString() { { "EN", fields[1] } }); db.PokedexInsertRegion(r); Console.WriteLine("Inserted region {0} {1}", r.ID, r.Name); }); // pkmncf_pokedex_locations SQLiteDataReader rdLocations = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, region_id, " + "(SELECT game_index FROM location_game_indices WHERE location_id = locations.id AND generation_id = 3) AS value3, " + "(SELECT game_index FROM location_game_indices WHERE location_id = locations.id AND generation_id = 4) AS value4, " + "(SELECT game_index FROM location_game_indices WHERE location_id = locations.id AND generation_id = 5) AS value5, " + "(SELECT game_index FROM location_game_indices WHERE location_id = locations.id AND generation_id = 6) AS value6, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 3) AS name_ko " + "FROM locations WHERE id NOT IN (522, 523, 524)"); // 522, 523, and 524 are duplicates of Kanto routes 19, 20, and 21. // todo: gba/colo/xd encounter location values while (rdLocations.Read()) { Location l = new Location(null, Convert.ToInt32(rdLocations["id"]), VeekunLocationToRegion(rdLocations), (int?)DatabaseExtender.Cast <long?>(rdLocations["value3"]), null, null, (int?)DatabaseExtender.Cast <long?>(rdLocations["value4"]), (int?)DatabaseExtender.Cast <long?>(rdLocations["value5"]), (int?)DatabaseExtender.Cast <long?>(rdLocations["value6"]), GetLocalizedString(rdLocations, "name_") ); db.PokedexInsertLocation(l); Console.WriteLine("Inserted location {0} {1}", l.ID, l.Name); } rdLocations.Close(); connVeekun.Close(); } #if DEBUG Console.ReadKey(); #endif }
static void Main(string[] args) { String veekunFilename; ConnectionStringSettings css; if (args.Length < 1) veekunFilename = "pokedex.sqlite"; else veekunFilename = args[0]; if (veekunFilename.Contains(';')) throw new NotSupportedException("The character ; in filenames is not supported."); if (veekunFilename.Contains('?')) { Console.WriteLine("Usage: VeekunImport [filename [connectionString providerName]]"); Console.WriteLine("filename: Filename of Veekun sqlite database. Default: pokedex.sqlite"); Console.WriteLine("connectionString: pkmnFoundations connection string. Default: from app.config"); Console.WriteLine("providerName: .NET classname of connection provider. Default: from app.config"); return; } if (args.Length < 3) css = ConfigurationManager.ConnectionStrings["pkmnFoundationsConnectionString"]; else css = new ConnectionStringSettings("", args[1], args[2]); Database db = Database.CreateInstance(css); using (SQLiteConnection connVeekun = new SQLiteConnection("Data Source=" + veekunFilename + "; Version=3")) { connVeekun.Open(); // General logic: // 1. run a query against veekun, populate a DataTable. // 2. foreach DataRow, instance a class from the PkmnFoundations.Pokedex namespace. // 3. call Database.AddToPokedex on that object. // todo: We need a way to rebuild specific tables // pkmncf_pokedex_pokemon_families // Obtain the families map. We will use it in a few places. Dictionary<int, int> familyMap = new Dictionary<int, int>(); List<int[]> familyList = new List<int[]>(); ProcessTSV("families_map.txt", 1, row => { // todo: allow for comments by stopping consumption of fields once one fails to parse. int[] fieldsInt = row.Fields.Select(s => Convert.ToInt32(s)).ToArray(); familyList.Add(fieldsInt); foreach (int x in fieldsInt) { // lineNumber is one-based, unlike familyList index. // species is the key, family ID is the value. // If any species is repeated in family_map.txt, this ought to fail. familyMap.Add(x, row.ValidLineNumber + 1); } }); // families from families.txt override default behaviour. List<Family> overrideFamilies = new List<Family>(); ProcessTSV("families.txt", 7, row => { String[] fields = row.Fields; overrideFamilies.Add(new Family(null, Convert.ToInt32(fields[0]), Convert.ToInt32(fields[1]), Convert.ToInt32(fields[2]), Convert.ToInt32(fields[3]), Convert.ToInt32(fields[4]), Convert.ToInt32(fields[5]), Convert.ToByte(fields[6]) )); }); // already sorted //someFamilies.Sort((f, other) => f.ID.CompareTo(other.ID)); int familyCount = familyList.Count; int nextOverrideIndex = 0; for (int familyId = 1; familyId <= familyCount; familyId++) { int basicSpeciesId = familyList[familyId - 1][0]; Family f; if (nextOverrideIndex < overrideFamilies.Count && overrideFamilies[nextOverrideIndex].ID == familyId) { // An override exists in the table; use it. f = overrideFamilies[nextOverrideIndex]; nextOverrideIndex++; } else { // No override exists so go with default: // Basic male/female are the same species which is the one listed first. // There is no baby species nor incense // (Non-incense babies are considered basic in this system anyway.) // Gender ratio comes from the basic species. byte genderRatio = (byte)Convert.ToInt32(connVeekun.ExecuteScalar("SELECT gender_rate FROM pokemon_species WHERE id = @id", new SQLiteParameter("@id", basicSpeciesId))); f = new Family(null, familyId, basicSpeciesId, basicSpeciesId, 0, 0, 0, genderRatio); } db.PokedexInsertFamily(f); String basic = (f.BasicMaleID != f.BasicFemaleID) ? String.Format(" {0}/{1}", f.BasicMaleID, f.BasicFemaleID) : String.Format(" {0}", f.BasicMaleID); String baby; if (f.BabyMaleID != f.BabyFemaleID) baby = String.Format(" {0}/{1} incense {2}", f.BabyMaleID, f.BabyFemaleID, f.IncenseID); else baby = (f.BabyMaleID == 0) ? "" : String.Format(" {0} incense {1}", f.BabyMaleID, f.IncenseID); String gender = (f.GenderRatio == 255) ? "genderless" : String.Format("{0}% female", (float)f.GenderRatio * 12.5f); Console.WriteLine("Inserted family {0}{1}{2} {3}", f.ID, basic, baby, gender); } // pkmncf_pokedex_pokemon SQLiteDataReader rdPokemon = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT " + "pokemon_species.id, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 1) AS name_ja, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 9) AS name_en, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 5) AS name_fr, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 8) AS name_it, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 6) AS name_de, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 7) AS name_es, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 3) AS name_ko, " + "growth_rate_id, gender_rate, " + "(SELECT egg_group_id FROM pokemon_egg_groups WHERE species_id = pokemon_species.id ORDER BY egg_group_id LIMIT 1) AS egg_group_1, " + "(SELECT egg_group_id FROM pokemon_egg_groups WHERE species_id = pokemon_species.id ORDER BY egg_group_id LIMIT 1, 1) AS egg_group_2, " + "hatch_counter, has_gender_differences " + "FROM pokemon_species " + "ORDER BY pokemon_species.id"); while (rdPokemon.Read()) { int id = Convert.ToInt32(rdPokemon["id"]); byte growth_rate_id = Convert.ToByte(rdPokemon["growth_rate_id"]); int gender_rate = Convert.ToInt32(rdPokemon["gender_rate"]); byte egg_group_1 = Convert.ToByte(rdPokemon["egg_group_1"]); byte egg_group_2 = 0; if (!(rdPokemon["egg_group_2"] is DBNull)) egg_group_2 = Convert.ToByte(rdPokemon["egg_group_2"]); int hatch_counter = Convert.ToInt32(rdPokemon["hatch_counter"]); byte has_gender_differences = Convert.ToByte(rdPokemon["has_gender_differences"]); // todo: Family ID Species s = new Species(null, id, familyMap[id], GetLocalizedString(rdPokemon, "name_"), (GrowthRates)growth_rate_id, (byte)gender_rate, (EggGroups)egg_group_1, (EggGroups)egg_group_2, (byte)hatch_counter, has_gender_differences != 0 ); db.PokedexInsertSpecies(s); Console.WriteLine("Inserted {0} {1} {2} {3} {4} {5}", s.NationalDex, s.Name.ToString(), s.GrowthRate, s.GenderRatio, s.EggSteps, s.GenderVariations); } rdPokemon.Close(); // pkmncf_pokedex_pokemon_forms Dictionary<int, byte> formValueMap = new Dictionary<int, byte>(); ProcessTSV("form_values.txt", 3, row => { String[] fields = row.Fields; formValueMap.Add(Convert.ToInt32(fields[1]), Convert.ToByte(fields[2])); }); SQLiteDataReader rdForms = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, " + "(SELECT species_id FROM pokemon WHERE id = pokemon_id) AS NationalDex, " + "form_order - 1 AS FormValue, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 1) AS name_ja, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 9) AS name_en, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 5) AS name_fr, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 8) AS name_it, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 6) AS name_de, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 7) AS name_es, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 3) AS name_ko, " + "form_identifier, " + "(SELECT height FROM pokemon WHERE id = pokemon_id) AS height, " + "(SELECT weight FROM pokemon WHERE id = pokemon_id) AS weight, " + "(SELECT base_experience FROM pokemon WHERE id = pokemon_id) AS experience " + "FROM pokemon_forms"); while (rdForms.Read()) { int id = Convert.ToInt32(rdForms["id"]); int NationalDex = Convert.ToInt32(rdForms["NationalDex"]); byte FormValue = Convert.ToByte(rdForms["FormValue"]); String form_identifier = rdForms["form_identifier"].ToString(); int height = Convert.ToInt32(rdForms["height"]); int weight = Convert.ToInt32(rdForms["weight"]); int experience = Convert.ToInt32(rdForms["experience"]); if (formValueMap.ContainsKey(id)) FormValue = formValueMap[id]; Form f = new Form(null, id, NationalDex, FormValue, GetLocalizedString(rdForms, "name_"), form_identifier, height, weight, experience ); db.PokedexInsertForm(f); Console.WriteLine("Inserted {0} {1} {2} {3} {4} {5:0.0}m {6:0.0}kg {7}", f.ID, f.SpeciesID, f.Value, f.Name.ToString(), f.Suffix, f.Height * 0.1f, f.Weight * 0.1f, f.Experience); } rdForms.Close(); // pkmncf_pokedex_pokemon_form_stats for (int generation = 1; generation <= GENERATIONS; generation++) { String filename = String.Format("form_stats{0}.txt", generation); ProcessTSV(filename, 15, row => { int[] fieldsInt = row.Fields.Select(s => Convert.ToInt32(s)).ToArray(); FormStats f = new FormStats(null, fieldsInt[0], (Generations)generation, fieldsInt[1], fieldsInt[2], new IntStatValues(fieldsInt[3], fieldsInt[4], fieldsInt[5], fieldsInt[6], fieldsInt[7], fieldsInt[8]), new ByteStatValues((byte)fieldsInt[9], (byte)fieldsInt[10], (byte)fieldsInt[11], (byte)fieldsInt[12], (byte)fieldsInt[13], (byte)fieldsInt[14]) ); db.PokedexInsertFormStats(f); Console.WriteLine("Inserted stats for {0} gen {1}", f.FormID, (int)f.MinGeneration); }); } // todo: pkmncf_pokedex_pokemon_evolutions // pkmncf_pokedex_types SQLiteDataReader rdTypes = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, damage_class_id, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 3) AS name_ko " + "FROM types ORDER BY id"); // http://stackoverflow.com/questions/27156585/failed-to-enable-constraints-without-dataadapter while (rdTypes.Read()) { int id = Convert.ToInt32(rdTypes["id"]); PkmnFoundations.Pokedex.Type t = new PkmnFoundations.Pokedex.Type(null, id, GetLocalizedString(rdTypes, "name_"), GetDamageClass(rdTypes)); db.PokedexInsertType(t); Console.WriteLine("Inserted type {0} {1} {2}", t.ID, t.Name.ToString(), t.DamageClass); } rdTypes.Close(); // pkmncf_pokedex_moves SQLiteDataReader rdMoves = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, type_id, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 3) AS name_ko, " + "damage_class_id, power, pp, accuracy, priority, target_id FROM moves"); while (rdMoves.Read()) { int id = Convert.ToInt32(rdMoves["id"]); int type_id = Convert.ToInt32(rdMoves["type_id"]); int damage_class_id = Convert.ToInt32(rdMoves["damage_class_id"]); short power = DatabaseExtender.Cast<short ?>(rdMoves["power"]) ?? 0; short pp = DatabaseExtender.Cast<short?>(rdMoves["pp"]) ?? 0; short accuracy = DatabaseExtender.Cast<short?>(rdMoves["accuracy"]) ?? 0; short priority = Convert.ToInt16(rdMoves["priority"]); int target_id = Convert.ToInt32(rdMoves["target_id"]); Move m = new Move(null, id, type_id, GetLocalizedString(rdMoves, "name_"), (DamageClass)damage_class_id, power, pp, accuracy, priority, (BattleTargets)target_id ); db.PokedexInsertMove(m); Console.WriteLine("Inserted move {0} {1}", m.ID, m.Name.ToString()); } // pkmncf_pokedex_abilities SQLiteDataReader rdAbilities = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 3) AS name_ko " + "FROM abilities WHERE is_main_series = 1"); while (rdAbilities.Read()) { int id = Convert.ToInt32(rdAbilities["id"]); Ability a = new Ability(null, id, GetLocalizedString(rdAbilities, "name_") ); db.PokedexInsertAbility(a); Console.WriteLine("Inserted ability {0} {1}", a.Value, a.Name.ToString()); } rdAbilities.Close(); // pkmncf_pokedex_items Dictionary<int, ItemLoading> items = new Dictionary<int, ItemLoading>(); for (int generation = 3; generation <= GENERATIONS; generation++) { String filename = String.Format("items{0}.txt", generation); ProcessTSV(filename, 3, row => { String[] fields = row.Fields; int id, thisGenId; String name = fields[1]; if (!Int32.TryParse(fields[0], out thisGenId) || !Int32.TryParse(fields[2], out id)) { Console.WriteLine("{0} line {1} has bad format, skipped.", filename, row.LineNumber); return; } ItemLoading theItem = null; if (!items.ContainsKey(id)) { theItem = new ItemLoading(id, name); items.Add(id, theItem); } theItem = theItem ?? items[id]; theItem.Name = name; // prefer newer names where available theItem.SetGenerationValue(thisGenId, generation); }); } // lookup Veekun ID number against some generation or another. Dictionary<int, ItemLoading> items3 = items .Where(i => i.Value.Value3 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value3, i => i.Value); Dictionary<int, ItemLoading> items4 = items .Where(i => i.Value.Value4 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value4, i => i.Value); Dictionary<int, ItemLoading> items5 = items .Where(i => i.Value.Value5 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value5, i => i.Value); Dictionary<int, ItemLoading> items6 = items .Where(i => i.Value.Value6 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value6, i => i.Value); // veekun has incorrect Gen3 indices for Helix/Dome fossil. // (Or they disagree with Bulbapedia which is my primary source) SQLiteDataReader rdItems = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, cost, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 3 AND NOT item_id IN (101, 102)) AS value3, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 4) AS value4, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 5) AS value5, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 6) AS value6, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 3) AS name_ko " + "FROM items"); Dictionary<int, ItemLoading>[] itemsGeneration = new Dictionary<int, ItemLoading>[] { null, null, items3, items4, items5, items6 }; while (rdItems.Read()) { List<ItemLoading> toProcess = new List<ItemLoading>(4); for (int generation = 3; generation <= GENERATIONS; generation++) { String col = String.Format("value{0}", generation); if (!(rdItems[col] is DBNull)) { Dictionary<int, ItemLoading> dict = itemsGeneration[generation - 1]; int value = Convert.ToInt32(rdItems[col]); if (dict.ContainsKey(value)) { ItemLoading il = dict[value]; il.NameLocalized = GetLocalizedString(rdItems, "name_"); il.Price = Convert.ToInt32(rdItems["cost"]); } } } } rdItems.Close(); foreach (ItemLoading il in items.Values) { LocalizedString name = il.NameLocalized; if (name == null) { name = new LocalizedString() { { "EN", il.Name } }; Console.WriteLine("Veekun database missing item {0} {1}. Non-English translations will be missing.", il.ID, name); } Item i = new Item(null, il.ID, il.Value3, il.Value4, il.Value5, il.Value6, il.Price, name); db.PokedexInsertItem(i); Console.WriteLine("Inserted item {0} {1}", i.ID, i.Name.ToString()); } // pkmncf_pokedex_ribbons Dictionary<int, RibbonLoading> ribbons = new Dictionary<int, RibbonLoading>(); if (!ProcessTSV("ribbons.txt", 3, row => { String[] fields = row.Fields; int id = Convert.ToInt32(fields[0]); ribbons.Add(id, new RibbonLoading(id, fields[1], fields[2])); })) Console.WriteLine("ribbons.txt not found. Not inserting any ribbons."); else { for (int generation = 3; generation <= GENERATIONS; generation++) { String filename = String.Format("ribbon_positions{0}.txt", generation); ProcessTSV(filename, 2, row => { String[] fields = row.Fields; int id = Convert.ToInt32(fields[0]); int position = Convert.ToInt32(fields[1]); if (!ribbons.ContainsKey(id)) { Console.WriteLine("Error: Ribbon ID {0} contained in {1} but not in ribbons.txt!", id, filename); return; } RibbonLoading r = ribbons[id]; r.SetGenerationPosition(position, generation); }); } foreach (KeyValuePair<int, RibbonLoading> pair in ribbons) { RibbonLoading r = pair.Value; db.PokedexInsertRibbon(new Ribbon(null, r.ID, new LocalizedString() { { "EN", r.Name } }, new LocalizedString() { { "EN", r.Description } }, r.Position3, r.Position4, r.Position5, r.Position6, null, null, null, null )); Console.WriteLine("Inserted ribbon {0} {1}", r.ID, r.Name); } } // pkmncf_pokedex_regions ProcessTSV("regions.txt", 2, row => { String[] fields = row.Fields; int id = Convert.ToInt32(fields[0]); Region r = new Region(null, id, new LocalizedString() { { "EN", fields[1] } }); db.PokedexInsertRegion(r); Console.WriteLine("Inserted region {0} {1}", r.ID, r.Name); }); // pkmncf_pokedex_locations SQLiteDataReader rdLocations = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, region_id, " + "(SELECT game_index FROM location_game_indices WHERE location_id = locations.id AND generation_id = 3) AS value3, " + "(SELECT game_index FROM location_game_indices WHERE location_id = locations.id AND generation_id = 4) AS value4, " + "(SELECT game_index FROM location_game_indices WHERE location_id = locations.id AND generation_id = 5) AS value5, " + "(SELECT game_index FROM location_game_indices WHERE location_id = locations.id AND generation_id = 6) AS value6, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM location_names WHERE location_names.location_id = locations.id AND local_language_id = 3) AS name_ko " + "FROM locations WHERE id NOT IN (522, 523, 524)"); // 522, 523, and 524 are duplicates of Kanto routes 19, 20, and 21. // todo: gba/colo/xd encounter location values while (rdLocations.Read()) { Location l = new Location(null, Convert.ToInt32(rdLocations["id"]), VeekunLocationToRegion(rdLocations), (int ?)DatabaseExtender.Cast<long?>(rdLocations["value3"]), null, null, (int?)DatabaseExtender.Cast<long?>(rdLocations["value4"]), (int?)DatabaseExtender.Cast<long?>(rdLocations["value5"]), (int?)DatabaseExtender.Cast<long?>(rdLocations["value6"]), GetLocalizedString(rdLocations, "name_") ); db.PokedexInsertLocation(l); Console.WriteLine("Inserted location {0} {1}", l.ID, l.Name); } rdLocations.Close(); connVeekun.Close(); } #if DEBUG Console.ReadKey(); #endif }
static void Main(string[] args) { String veekunFilename; ConnectionStringSettings css; if (args.Length < 1) { veekunFilename = "pokedex.sqlite"; } else { veekunFilename = args[0]; } if (veekunFilename.Contains(';')) { throw new NotSupportedException("The character ; in filenames is not supported."); } if (veekunFilename.Contains('?')) { Console.WriteLine("Usage: VeekunImport [filename [connectionString providerName]]"); Console.WriteLine("filename: Filename of Veekun sqlite database. Default: pokedex.sqlite"); Console.WriteLine("connectionString: pkmnFoundations connection string. Default: from app.config"); Console.WriteLine("providerName: .NET classname of connection provider. Default: from app.config"); return; } if (args.Length < 3) { css = ConfigurationManager.ConnectionStrings["pkmnFoundationsConnectionString"]; } else { css = new ConnectionStringSettings("", args[1], args[2]); } Database db = Database.CreateInstance(css); using (SQLiteConnection connVeekun = new SQLiteConnection("Data Source=" + veekunFilename + "; Version=3")) { connVeekun.Open(); // General logic: // 1. run a query against veekun, populate a DataTable. // 2. foreach DataRow, instance a class from the PkmnFoundations.Pokedex namespace. // 3. call Database.AddToPokedex on that object. // pkmncf_pokedex_pokemon_families // Obtain the families map. We will use it in a few places. Dictionary <int, int> familyMap = new Dictionary <int, int>(); List <int[]> familyList = new List <int[]>(); using (FileStream fs = File.Open("families_map.txt", FileMode.Open)) { StreamReader sr = new StreamReader(fs, Encoding.UTF8); int lineNumber = 0; String line; while ((line = sr.ReadLine()) != null) { lineNumber++; String[] fields = line.Split('\t'); // todo: allow and reject blank lines at the end. if (fields.Length == 0) { throw new Exception("families_map.txt has a blank line."); } int[] fieldsInt = fields.Select(s => Convert.ToInt32(s)).ToArray(); familyList.Add(fieldsInt); foreach (int x in fieldsInt) { // lineNumber is one-based, unlike familyList index. // species is the key, family ID is the value. // If any species is repeated in family_map.txt, this ought to fail. familyMap.Add(x, lineNumber); } } } // families from families.txt override default behaviour. List <Family> overrideFamilies = new List <Family>(); using (FileStream fs = File.Open("families.txt", FileMode.Open)) { StreamReader sr = new StreamReader(fs, Encoding.UTF8); String line; while ((line = sr.ReadLine()) != null) { String[] fields = line.Split('\t'); overrideFamilies.Add(new Family(null, Convert.ToInt32(fields[0]), Convert.ToInt32(fields[1]), Convert.ToInt32(fields[2]), Convert.ToInt32(fields[3]), Convert.ToInt32(fields[4]), Convert.ToInt32(fields[5]), Convert.ToByte(fields[6]) )); } } // already sorted //someFamilies.Sort((f, other) => f.ID.CompareTo(other.ID)); int familyCount = familyList.Count; int nextOverrideIndex = 0; for (int familyId = 1; familyId <= familyCount; familyId++) { int basicSpeciesId = familyList[familyId - 1][0]; Family f; if (nextOverrideIndex < overrideFamilies.Count && overrideFamilies[nextOverrideIndex].ID == familyId) { // An override exists in the table; use it. f = overrideFamilies[nextOverrideIndex]; nextOverrideIndex++; } else { // No override exists so go with default: // Basic male/female are the same species which is the one listed first. // There is no baby species nor incense // (Non-incense babies are considered basic in this system anyway.) // Gender ratio comes from the basic species. byte genderRatio = (byte)Convert.ToInt32(connVeekun.ExecuteScalar("SELECT gender_rate FROM pokemon_species WHERE id = @id", new SQLiteParameter("@id", basicSpeciesId))); f = new Family(null, familyId, basicSpeciesId, basicSpeciesId, 0, 0, 0, genderRatio); } db.PokedexInsertFamily(f); String basic = (f.BasicMaleID != f.BasicFemaleID) ? String.Format(" {0}/{1}", f.BasicMaleID, f.BasicFemaleID) : String.Format(" {0}", f.BasicMaleID); String baby; if (f.BabyMaleID != f.BabyFemaleID) { baby = String.Format(" {0}/{1} incense {2}", f.BabyMaleID, f.BabyFemaleID, f.IncenseID); } else { baby = (f.BabyMaleID == 0) ? "" : String.Format(" {0} incense {1}", f.BabyMaleID, f.IncenseID); } String gender = (f.GenderRatio == 255) ? "genderless" : String.Format("{0}% female", (float)f.GenderRatio * 12.5f); Console.WriteLine("Inserted family {0}{1}{2} {3}", f.ID, basic, baby, gender); } // pkmncf_pokedex_pokemon SQLiteDataReader rdPokemon = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT " + "pokemon_species.id, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 1) AS name_ja, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 9) AS name_en, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 5) AS name_fr, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 8) AS name_it, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 6) AS name_de, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 7) AS name_es, " + "(SELECT pokemon_species_names.name FROM pokemon_species_names WHERE pokemon_species_names.pokemon_species_id = pokemon_species.id AND local_language_id = 3) AS name_ko, " + "growth_rate_id, gender_rate, " + "(SELECT egg_group_id FROM pokemon_egg_groups WHERE species_id = pokemon_species.id ORDER BY egg_group_id LIMIT 1) AS egg_group_1, " + "(SELECT egg_group_id FROM pokemon_egg_groups WHERE species_id = pokemon_species.id ORDER BY egg_group_id LIMIT 1, 1) AS egg_group_2, " + "hatch_counter, has_gender_differences " + "FROM pokemon_species " + "ORDER BY pokemon_species.id"); while (rdPokemon.Read()) { int id = Convert.ToInt32(rdPokemon["id"]); byte growth_rate_id = Convert.ToByte(rdPokemon["growth_rate_id"]); int gender_rate = Convert.ToInt32(rdPokemon["gender_rate"]); byte egg_group_1 = Convert.ToByte(rdPokemon["egg_group_1"]); byte egg_group_2 = 0; if (!(rdPokemon["egg_group_2"] is DBNull)) { egg_group_2 = Convert.ToByte(rdPokemon["egg_group_2"]); } int hatch_counter = Convert.ToInt32(rdPokemon["hatch_counter"]); byte has_gender_differences = Convert.ToByte(rdPokemon["has_gender_differences"]); // todo: Family ID Species s = new Species(null, id, familyMap[id], GetLocalizedString(rdPokemon, "name_"), (GrowthRates)growth_rate_id, (byte)gender_rate, (EggGroups)egg_group_1, (EggGroups)egg_group_2, (byte)hatch_counter, has_gender_differences != 0 ); db.PokedexInsertSpecies(s); Console.WriteLine("Inserted {0} {1} {2} {3} {4} {5}", s.NationalDex, s.Name.ToString(), s.GrowthRate, s.GenderRatio, s.EggSteps, s.GenderVariations); } rdPokemon.Close(); // pkmncf_pokedex_pokemon_forms SQLiteDataReader rdForms = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, " + "(SELECT species_id FROM pokemon WHERE id = pokemon_id) AS NationalDex, " + "form_order - 1 AS FormValue, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 1) AS name_ja, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 9) AS name_en, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 5) AS name_fr, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 8) AS name_it, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 6) AS name_de, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 7) AS name_es, " + "(SELECT pokemon_form_names.form_name FROM pokemon_form_names WHERE pokemon_form_names.pokemon_form_id = pokemon_forms.id AND local_language_id = 3) AS name_ko, " + "form_identifier, " + "(SELECT height FROM pokemon WHERE id = pokemon_id) AS height, " + "(SELECT weight FROM pokemon WHERE id = pokemon_id) AS weight, " + "(SELECT base_experience FROM pokemon WHERE id = pokemon_id) AS experience " + "FROM pokemon_forms"); while (rdForms.Read()) { int id = Convert.ToInt32(rdForms["id"]); int NationalDex = Convert.ToInt32(rdForms["NationalDex"]); byte FormValue = Convert.ToByte(rdForms["FormValue"]); String form_identifier = rdForms["form_identifier"].ToString(); int height = Convert.ToInt32(rdForms["height"]); int weight = Convert.ToInt32(rdForms["weight"]); int experience = Convert.ToInt32(rdForms["experience"]); Form f = new Form(null, id, NationalDex, FormValue, GetLocalizedString(rdForms, "name_"), form_identifier, height, weight, experience ); db.PokedexInsertForm(f); Console.WriteLine("Inserted {0} {1} {2} {3} {4} {5:0.0}m {6:0.0}kg {7}", f.ID, f.NationalDex, f.Value, f.Name.ToString(), f.Suffix, f.Height * 0.1f, f.Weight * 0.1f, f.Experience); } rdForms.Close(); // todo: pkmncf_pokedex_pokemon_form_stats_x // todo: pkmncf_pokedex_pokemon_families // todo: pkmncf_pokedex_pokemon_evolutions // pkmncf_pokedex_types SQLiteDataReader rdTypes = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, damage_class_id, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM type_names WHERE type_names.type_id = types.id AND local_language_id = 3) AS name_ko " + "FROM types ORDER BY id"); // http://stackoverflow.com/questions/27156585/failed-to-enable-constraints-without-dataadapter while (rdTypes.Read()) { int id = Convert.ToInt32(rdTypes["id"]); PkmnFoundations.Pokedex.Type t = new PkmnFoundations.Pokedex.Type(null, id, GetLocalizedString(rdTypes, "name_"), GetDamageClass(rdTypes)); db.PokedexInsertType(t); Console.WriteLine("Inserted {0} {1} {2}", t.ID, t.Name.ToString(), t.DamageClass); } rdTypes.Close(); // pkmncf_pokedex_moves SQLiteDataReader rdMoves = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, type_id, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM move_names WHERE move_names.move_id = moves.id AND local_language_id = 3) AS name_ko, " + "damage_class_id, power, pp, accuracy, priority, target_id FROM moves"); while (rdMoves.Read()) { int id = Convert.ToInt32(rdMoves["id"]); int type_id = Convert.ToInt32(rdMoves["type_id"]); int damage_class_id = Convert.ToInt32(rdMoves["damage_class_id"]); short power = DatabaseExtender.Coalesce(rdMoves["power"], (short)0); short pp = DatabaseExtender.Coalesce(rdMoves["pp"], (short)0); short accuracy = DatabaseExtender.Coalesce(rdMoves["accuracy"], (short)0); short priority = Convert.ToInt16(rdMoves["priority"]); int target_id = Convert.ToInt32(rdMoves["target_id"]); Move m = new Move(null, id, type_id, GetLocalizedString(rdMoves, "name_"), (DamageClass)damage_class_id, power, pp, accuracy, priority, (BattleTargets)target_id ); db.PokedexInsertMove(m); Console.WriteLine("Inserted {0} {1}", m.ID, m.Name.ToString()); } // pkmncf_pokedex_abilities SQLiteDataReader rdAbilities = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM ability_names WHERE ability_names.ability_id = abilities.id AND local_language_id = 3) AS name_ko " + "FROM abilities WHERE is_main_series = 1"); while (rdAbilities.Read()) { int id = Convert.ToInt32(rdAbilities["id"]); Ability a = new Ability(null, id, GetLocalizedString(rdAbilities, "name_") ); db.PokedexInsertAbility(a); Console.WriteLine("Inserted {0} {1}", a.Value, a.Name.ToString()); } rdAbilities.Close(); // pkmncf_pokedex_items Dictionary <int, ItemLoading> items = new Dictionary <int, ItemLoading>(); for (int generation = 3; generation < 6; generation++) { String filename = String.Format("items{0}.txt", generation); if (!File.Exists(filename)) { Console.WriteLine("File {0} not found, skipped.", filename); continue; } using (FileStream fs = File.Open(filename, FileMode.Open)) { StreamReader sr = new StreamReader(fs, Encoding.UTF8); int lineNumber = -1; String line; while ((line = sr.ReadLine()) != null) { lineNumber++; String[] fields = line.Split('\t'); if (fields.Length != 3) { Console.WriteLine("{0} line {1} has bad format, skipped.", filename, lineNumber); continue; } int id, thisGenId; String name = fields[1]; if (!Int32.TryParse(fields[0], out thisGenId) || !Int32.TryParse(fields[2], out id)) { Console.WriteLine("{0} line {1} has bad format, skipped.", filename, lineNumber); continue; } ItemLoading theItem = null; if (!items.ContainsKey(id)) { theItem = new ItemLoading(id, name); items.Add(id, theItem); } theItem = theItem ?? items[id]; theItem.Name = name; // prefer newer names where available switch (generation) { // todo: maybe use an array or dictionary for these fields. case 3: theItem.Value3 = thisGenId; break; case 4: theItem.Value4 = thisGenId; break; case 5: theItem.Value5 = thisGenId; break; case 6: theItem.Value6 = thisGenId; break; } } } } // lookup Veekun ID number against some generation or another. Dictionary <int, ItemLoading> items3 = items .Where(i => i.Value.Value3 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value3, i => i.Value); Dictionary <int, ItemLoading> items4 = items .Where(i => i.Value.Value4 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value4, i => i.Value); Dictionary <int, ItemLoading> items5 = items .Where(i => i.Value.Value5 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value5, i => i.Value); Dictionary <int, ItemLoading> items6 = items .Where(i => i.Value.Value6 != null && i.Value.NameLocalized == null) .ToDictionary(i => (int)i.Value.Value6, i => i.Value); SQLiteDataReader rdItems = (SQLiteDataReader)connVeekun.ExecuteReader("SELECT id, cost, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 3) AS value3, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 4) AS value4, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 5) AS value5, " + "(SELECT game_index FROM item_game_indices WHERE item_id = items.id AND generation_id = 6) AS value6, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 1) AS name_ja, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 9) AS name_en, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 5) AS name_fr, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 8) AS name_it, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 6) AS name_de, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 7) AS name_es, " + "(SELECT name FROM item_names WHERE item_names.item_id = items.id AND local_language_id = 3) AS name_ko " + "FROM items"); Dictionary <int, ItemLoading>[] itemsGeneration = new Dictionary <int, ItemLoading>[] { null, null, items3, items4, items5, items6 }; while (rdItems.Read()) { List <ItemLoading> toProcess = new List <ItemLoading>(4); for (int generation = 3; generation < 7; generation++) { String col = String.Format("value{0}", generation); if (!(rdItems[col] is DBNull)) { Dictionary <int, ItemLoading> dict = itemsGeneration[generation - 1]; int value = Convert.ToInt32(rdItems[col]); if (dict.ContainsKey(value)) { ItemLoading il = dict[value]; il.NameLocalized = GetLocalizedString(rdItems, "name_"); il.Price = Convert.ToInt32(rdItems["cost"]); } } } } rdItems.Close(); foreach (ItemLoading il in items.Values) { LocalizedString name = il.NameLocalized; if (name == null) { name = new LocalizedString() { { "EN", il.Name } }; Console.WriteLine("Veekun database missing item {0} {1}. Non-English translations will be missing.", il.ID, name); } Item i = new Item(null, il.ID, il.Value3, il.Value4, il.Value5, il.Value6, il.Price, name); db.PokedexInsertItem(i); Console.WriteLine("Inserted {0} {1}", i.ID, i.Name.ToString()); } connVeekun.Close(); } Console.ReadKey(); }