Merge branch 'schema-sanity'

This commit is contained in:
Eevee 2011-03-28 19:14:24 -07:00
commit 4daa6ab0c3
59 changed files with 787 additions and 547 deletions

View file

@ -1,4 +1,4 @@
ability_changelog_id,language_id,effect ability_changelog_id,local_language_id,effect
1,9,Has no effect in battle. 1,9,Has no effect in battle.
2,9,Does not prevent regular KOs from full [HP]{mechanic}. 2,9,Does not prevent regular KOs from full [HP]{mechanic}.
3,9,Has no overworld effect. 3,9,Has no overworld effect.

1 ability_changelog_id language_id local_language_id effect
2 1 9 Has no effect in battle.
3 2 9 Does not prevent regular KOs from full [HP]{mechanic}.
4 3 9 Has no overworld effect.

View file

@ -1,4 +1,4 @@
ability_id,language_id,name ability_id,local_language_id,name
1,1,あくしゅう 1,1,あくしゅう
1,5,Puanteur 1,5,Puanteur
1,6,Duftnote 1,6,Duftnote
1 ability_id language_id local_language_id name
2 1 1 あくしゅう
3 1 5 Puanteur
4 1 6 Duftnote

View file

@ -1,4 +1,4 @@
ability_id,language_id,effect,short_effect ability_id,local_language_id,effect,short_effect
1,9,"This Pokémon's moves have approximately a 10% chance to make the target [flinch]{mechanic}. 1,9,"This Pokémon's moves have approximately a 10% chance to make the target [flinch]{mechanic}.
This ability does not stack with a held [King's Rock]{item}. This ability does not stack with a held [King's Rock]{item}.

1 ability_id language_id local_language_id effect short_effect
2 1 9 This Pokémon's moves have approximately a 10% chance to make the target [flinch]{mechanic}. This ability does not stack with a held [King's Rock]{item}. Overworld: The wild encounter rate is halved while this Pokémon is in the party. Has a chance of making the opponent [flinch]{mechanic} when attacking.
3 2 9 The [weather]{mechanic} changes to [rain]{mechanic} when this Pokémon enters battle and does not end unless replaced by another weather condition. If multiple Pokémon with this ability, [Drought]{ability}, [Sand Stream]{ability}, or [Snow Warning]{ability} are sent out at the same time, the abilities will activate in order of [Speed]{mechanic}, respecting [Trick Room]{move}. Each ability's weather will cancel the previous weather, and only the weather summoned by the slowest of the Pokémon will stay. Summons [rain]{mechanic} that lasts indefinitely upon entering battle.
4 3 9 This Pokémon's [Speed]{mechanic} rises one [stage]{mechanic:stat modifier} after each turn. Raises [Speed]{mechanic} one [stage]{mechanic:stat modifier} after each turn.

View file

@ -1,4 +1,4 @@
berry_firmness_id,language_id,name berry_firmness_id,local_language_id,name
1,9,Very Soft 1,9,Very Soft
2,9,Soft 2,9,Soft
3,9,Hard 3,9,Hard
1 berry_firmness_id language_id local_language_id name
2 1 9 9 Very Soft
3 2 9 9 Soft
4 3 9 9 Hard

View file

@ -1,4 +1,4 @@
contest_effect_id,language_id,flavor_text,effect contest_effect_id,local_language_id,flavor_text,effect
1,9,A highly appealing move.,Gives a high number of appeal points wth no other effects. 1,9,A highly appealing move.,Gives a high number of appeal points wth no other effects.
2,9,Affected by how well the appeal in front goes.,"If the Pokémon that appealed before the user earned less than three appeal points, user earns six; if three, user earns three; if more than three, user earns none." 2,9,Affected by how well the appeal in front goes.,"If the Pokémon that appealed before the user earned less than three appeal points, user earns six; if three, user earns three; if more than three, user earns none."
3,9,"After this move, the user is more easily startled.","If the user is jammed this turn after using this move, it will receive twice as many jam points." 3,9,"After this move, the user is more easily startled.","If the user is jammed this turn after using this move, it will receive twice as many jam points."

1 contest_effect_id language_id local_language_id flavor_text effect
2 1 9 A highly appealing move. Gives a high number of appeal points wth no other effects.
3 2 9 Affected by how well the appeal in front goes. If the Pokémon that appealed before the user earned less than three appeal points, user earns six; if three, user earns three; if more than three, user earns none.
4 3 9 After this move, the user is more easily startled. If the user is jammed this turn after using this move, it will receive twice as many jam points.

View file

@ -1,4 +1,4 @@
contest_type_id,language_id,name,flavor,color contest_type_id,local_language_id,name,flavor,color
1,9,Cool,Spicy,Red 1,9,Cool,Spicy,Red
2,9,Beauty,Dry,Blue 2,9,Beauty,Dry,Blue
3,9,Cute,Sweet,Pink 3,9,Cute,Sweet,Pink
1 contest_type_id language_id local_language_id name flavor color
2 1 9 9 Cool Spicy Red
3 2 9 9 Beauty Dry Blue
4 3 9 9 Cute Sweet Pink

View file

@ -1,4 +1,4 @@
egg_group_id,language_id,name egg_group_id,local_language_id,name
1,9,Monster 1,9,Monster
2,9,Water 1 2,9,Water 1
3,9,Bug 3,9,Bug

1 egg_group_id language_id local_language_id name
2 1 9 Monster
3 2 9 Water 1
4 3 9 Bug

View file

@ -1,4 +1,4 @@
encounter_condition_id,language_id,name encounter_condition_id,local_language_id,name
1,9,Swarm 1,9,Swarm
2,9,Time of day 2,9,Time of day
3,9,PokeRadar 3,9,PokeRadar

1 encounter_condition_id language_id local_language_id name
2 1 9 9 Swarm
3 2 9 9 Time of day
4 3 9 9 PokeRadar

View file

@ -1,4 +1,4 @@
encounter_condition_value_id,language_id,name encounter_condition_value_id,local_language_id,name
1,9,During a swarm 1,9,During a swarm
2,9,Not during a swarm 2,9,Not during a swarm
3,9,In the morning 3,9,In the morning

1 encounter_condition_value_id language_id local_language_id name
2 1 9 During a swarm
3 2 9 Not during a swarm
4 3 9 In the morning

View file

@ -1,4 +1,4 @@
encounter_terrain_id,language_id,name encounter_terrain_id,local_language_id,name
1,9,Walking in tall grass or a cave 1,9,Walking in tall grass or a cave
2,9,Fishing with an Old Rod 2,9,Fishing with an Old Rod
3,9,Fishing with a Good Rod 3,9,Fishing with a Good Rod

1 encounter_terrain_id language_id local_language_id name
2 1 9 9 Walking in tall grass or a cave
3 2 9 9 Fishing with an Old Rod
4 3 9 9 Fishing with a Good Rod

View file

@ -1,4 +1,4 @@
evolution_trigger_id,language_id,name evolution_trigger_id,local_language_id,name
1,9,Level_up 1,9,Level_up
2,9,Trade 2,9,Trade
3,9,Use_item 3,9,Use_item

1 evolution_trigger_id language_id local_language_id name
2 1 9 9 Level_up
3 2 9 9 Trade
4 3 9 9 Use_item

View file

@ -1,4 +1,4 @@
generation_id,language_id,name generation_id,local_language_id,name
1,9,Generation I 1,9,Generation I
2,9,Generation II 2,9,Generation II
3,9,Generation III 3,9,Generation III
1 generation_id language_id local_language_id name
2 1 9 9 Generation I
3 2 9 9 Generation II
4 3 9 9 Generation III

View file

@ -1,4 +1,4 @@
growth_rate_id,language_id,name growth_rate_id,local_language_id,name
1,9,slow 1,9,slow
2,9,medium 2,9,medium
3,9,fast 3,9,fast

1 growth_rate_id language_id local_language_id name
2 1 9 9 slow
3 2 9 9 medium
4 3 9 9 fast

View file

@ -1,4 +1,4 @@
item_category_id,language_id,name item_category_id,local_language_id,name
1,9,Stat boosts 1,9,Stat boosts
2,9,Effort drop 2,9,Effort drop
3,9,Medicine 3,9,Medicine

1 item_category_id language_id local_language_id name
2 1 9 Stat boosts
3 2 9 Effort drop
4 3 9 Medicine

View file

@ -1,4 +1,4 @@
item_flag_id,language_id,name,description item_flag_id,local_language_id,name,description
1,9,Countable,Has a count in the bag 1,9,Countable,Has a count in the bag
2,9,Consumable,Consumed when used 2,9,Consumable,Consumed when used
3,9,Usable_overworld,Usable outside battle 3,9,Usable_overworld,Usable outside battle

1 item_flag_id language_id local_language_id name description
2 1 9 Countable Has a count in the bag
3 2 9 Consumable Consumed when used
4 3 9 Usable_overworld Usable outside battle

View file

@ -1,4 +1,4 @@
item_fling_effect_id,language_id,effect item_fling_effect_id,local_language_id,effect
1,9,Badly poisons the target. 1,9,Badly poisons the target.
2,9,Burns the target. 2,9,Burns the target.
3,9,Immediately activates the berry's effect on the target. 3,9,Immediately activates the berry's effect on the target.

1 item_fling_effect_id language_id local_language_id effect
2 1 9 9 Badly poisons the target.
3 2 9 9 Burns the target.
4 3 9 9 Immediately activates the berry's effect on the target.

View file

@ -1,4 +1,4 @@
item_id,generation_id,internal_id item_id,generation_id,game_index
1,3,1 1,3,1
1,4,1 1,4,1
1,5,1 1,5,1
1 item_id generation_id internal_id game_index
2 1 3 1
3 1 4 1
4 1 5 1

View file

@ -1,4 +1,4 @@
item_id,language_id,name item_id,local_language_id,name
1,1,マスターボール 1,1,マスターボール
1,5,Master Ball 1,5,Master Ball
1,6,Meisterball 1,6,Meisterball
1 item_id language_id local_language_id name
2 1 1 マスターボール
3 1 5 Master Ball
4 1 6 Meisterball

View file

@ -1,4 +1,4 @@
item_pocket_id,language_id,name item_pocket_id,local_language_id,name
1,9,Items 1,9,Items
2,9,Medicine 2,9,Medicine
3,9,Poké Balls 3,9,Poké Balls
1 item_pocket_id language_id local_language_id name
2 1 9 Items
3 2 9 Medicine
4 3 9 Poké Balls

View file

@ -1,4 +1,4 @@
item_id,language_id,short_effect,effect item_id,local_language_id,short_effect,effect
1,9,,In battle: Captures one Pokémon without fail. Has a capture rate of 255. 1,9,,In battle: Captures one Pokémon without fail. Has a capture rate of 255.
2,9,,In battle: Attempts to capture one Pokémon. Has a capture rate of 2. 2,9,,In battle: Attempts to capture one Pokémon. Has a capture rate of 2.
3,9,,In battle: Attempts to capture one Pokémon. Has a capture rate of 1.5. 3,9,,In battle: Attempts to capture one Pokémon. Has a capture rate of 1.5.

1 item_id language_id local_language_id short_effect effect
2 1 9 In battle: Captures one Pokémon without fail. Has a capture rate of 255.
3 2 9 In battle: Attempts to capture one Pokémon. Has a capture rate of 2.
4 3 9 In battle: Attempts to capture one Pokémon. Has a capture rate of 1.5.

View file

@ -1,4 +1,4 @@
lang_id,language_id,name language_id,local_language_id,name
1,9,Japanese 1,9,Japanese
2,9,Official Roomaji 2,9,Official Roomaji
3,9,Korean 3,9,Korean
1 lang_id language_id local_language_id name
2 1 9 1 9 Japanese
3 2 9 2 9 Official Roomaji
4 3 9 3 9 Korean

View file

@ -1,4 +1,4 @@
location_area_id,language_id,name location_area_id,local_language_id,name
1,9, 1,9,
2,9, 2,9,
3,9, 3,9,

1 location_area_id language_id local_language_id name
2 1 9
3 2 9
4 3 9

View file

@ -1,4 +1,4 @@
id,location_id,internal_id,identifier id,location_id,game_index,identifier
1,1,1, 1,1,1,
2,2,2, 2,2,2,
3,3,3, 3,3,3,

1 id location_id internal_id game_index identifier
2 1 1 1
3 2 2 2
4 3 3 3

View file

@ -1,4 +1,4 @@
location_id,generation_id,internal_id location_id,generation_id,game_index
1,4,7 1,4,7
2,4,9 2,4,9
3,4,11 3,4,11
1 location_id generation_id internal_id game_index
2 1 4 7
3 2 4 9
4 3 4 11

View file

@ -1,4 +1,4 @@
location_id,language_id,name location_id,local_language_id,name
1,9,Canalave City 1,9,Canalave City
2,9,Eterna City 2,9,Eterna City
3,9,Pastoria City 3,9,Pastoria City
1 location_id language_id local_language_id name
2 1 9 Canalave City
3 2 9 Eterna City
4 3 9 Pastoria City

View file

@ -1,4 +1,4 @@
move_battle_style_id,language_id,name move_battle_style_id,local_language_id,name
1,9,Attack 1,9,Attack
2,9,Defense 2,9,Defense
3,9,Support 3,9,Support

1 move_battle_style_id language_id local_language_id name
2 1 9 9 Attack
3 2 9 9 Defense
4 3 9 9 Support

View file

@ -1,4 +1,4 @@
move_damage_class_id,language_id,name,description move_damage_class_id,local_language_id,name,description
1,9,non-damaging,No damage 1,9,non-damaging,No damage
2,9,physical,"Physical damage, controlled by Attack and Defense" 2,9,physical,"Physical damage, controlled by Attack and Defense"
3,9,special,"Special damage, controlled by Special Attack and Special Defense" 3,9,special,"Special damage, controlled by Special Attack and Special Defense"

1 move_damage_class_id language_id local_language_id name description
2 1 9 9 non-damaging No damage
3 2 9 9 physical Physical damage, controlled by Attack and Defense
4 3 9 9 special Special damage, controlled by Special Attack and Special Defense

View file

@ -1,4 +1,4 @@
move_effect_category_id,language_id,name move_effect_category_id,local_language_id,name
1,9,Regular damage 1,9,Regular damage
2,9,Power varies 2,9,Power varies
3,9,Special damage 3,9,Special damage

1 move_effect_category_id language_id local_language_id name
2 1 9 Regular damage
3 2 9 Power varies
4 3 9 Special damage

View file

@ -1,4 +1,4 @@
move_effect_changelog_id,language_id,effect move_effect_changelog_id,local_language_id,effect
1,9,"Halves the target's [Defense]{mechanic} for damage calculation, which is similar to doubling the attack's [power]{mechanic}." 1,9,"Halves the target's [Defense]{mechanic} for damage calculation, which is similar to doubling the attack's [power]{mechanic}."
2,9,Hits Pokémon under the effects of [Dig]{move} and [Fly]{move}. 2,9,Hits Pokémon under the effects of [Dig]{move} and [Fly]{move}.
3,9,Does nothing in trainer battles. 3,9,Does nothing in trainer battles.

1 move_effect_changelog_id language_id local_language_id effect
2 1 9 Halves the target's [Defense]{mechanic} for damage calculation, which is similar to doubling the attack's [power]{mechanic}.
3 2 9 Hits Pokémon under the effects of [Dig]{move} and [Fly]{move}.
4 3 9 Does nothing in trainer battles.

View file

@ -1,4 +1,4 @@
move_effect_id,language_id,short_effect,effect move_effect_id,local_language_id,short_effect,effect
1,9,Inflicts regular damage with no additional effect.,Inflicts [regular damage]{mechanic}. 1,9,Inflicts regular damage with no additional effect.,Inflicts [regular damage]{mechanic}.
2,9,Puts the target to sleep.,Puts the target to [sleep]{mechanic}. 2,9,Puts the target to sleep.,Puts the target to [sleep]{mechanic}.
3,9,Has a $effect_chance% chance to poison the target.,Inflicts [regular damage]{mechanic}. Has a $effect_chance% chance to [poison]{mechanic} the target. 3,9,Has a $effect_chance% chance to poison the target.,Inflicts [regular damage]{mechanic}. Has a $effect_chance% chance to [poison]{mechanic} the target.

1 move_effect_id language_id local_language_id short_effect effect
2 1 9 Inflicts regular damage with no additional effect. Inflicts [regular damage]{mechanic}.
3 2 9 Puts the target to sleep. Puts the target to [sleep]{mechanic}.
4 3 9 Has a $effect_chance% chance to poison the target. Inflicts [regular damage]{mechanic}. Has a $effect_chance% chance to [poison]{mechanic} the target.

View file

@ -1,4 +1,4 @@
move_flag_type_id,language_id,name,description move_flag_type_id,local_language_id,name,description
1,9,Makes contact,"User touches the target. This triggers some abilities (e.g., [Static]{ability}) and items (e.g., [Sticky Barb]{item})." 1,9,Makes contact,"User touches the target. This triggers some abilities (e.g., [Static]{ability}) and items (e.g., [Sticky Barb]{item})."
2,9,Has a charging turn,This move has a charging turn that can be skipped with a [Power Herb]{item}. 2,9,Has a charging turn,This move has a charging turn that can be skipped with a [Power Herb]{item}.
3,9,Must recharge,"The turn after this move is used, the Pokémon's action is skipped so it can recharge." 3,9,Must recharge,"The turn after this move is used, the Pokémon's action is skipped so it can recharge."

1 move_flag_type_id language_id local_language_id name description
2 1 9 Makes contact User touches the target. This triggers some abilities (e.g., [Static]{ability}) and items (e.g., [Sticky Barb]{item}).
3 2 9 Has a charging turn This move has a charging turn that can be skipped with a [Power Herb]{item}.
4 3 9 Must recharge The turn after this move is used, the Pokémon's action is skipped so it can recharge.

View file

@ -1,4 +1,4 @@
move_meta_ailment_id,language_id,name move_meta_ailment_id,local_language_id,name
-1,9,???? -1,9,????
0,9,none 0,9,none
1,9,Paralysis 1,9,Paralysis
1 move_meta_ailment_id language_id local_language_id name
2 -1 9 ????
3 0 9 none
4 1 9 Paralysis

View file

@ -1,4 +1,4 @@
move_meta_category_id,language_id,description move_meta_category_id,local_language_id,description
0,9,Inflicts damage 0,9,Inflicts damage
1,9,No damage; inflicts status ailment 1,9,No damage; inflicts status ailment
2,9,No damage; lowers target's stats or raises user's stats 2,9,No damage; lowers target's stats or raises user's stats

1 move_meta_category_id language_id local_language_id description
2 0 9 Inflicts damage
3 1 9 No damage; inflicts status ailment
4 2 9 No damage; lowers target's stats or raises user's stats

View file

@ -1,4 +1,4 @@
move_id,language_id,name move_id,local_language_id,name
1,1,はたく 1,1,はたく
1,5,Écras'Face 1,5,Écras'Face
1,6,Pfund 1,6,Pfund
1 move_id language_id local_language_id name
2 1 1 はたく
3 1 5 Écras'Face
4 1 6 Pfund

View file

@ -1,4 +1,4 @@
move_target_id,language_id,name,description move_target_id,local_language_id,name,description
1,9,Specific move,One specific move. How this move is chosen depends upon on the move being used. 1,9,Specific move,One specific move. How this move is chosen depends upon on the move being used.
2,9,Selected Pokémon,"One other Pokémon on the field, selected by the trainer. Stolen moves reuse the same target." 2,9,Selected Pokémon,"One other Pokémon on the field, selected by the trainer. Stolen moves reuse the same target."
3,9,Ally,The user's ally (if any). 3,9,Ally,The user's ally (if any).

1 move_target_id language_id local_language_id name description
2 1 9 Specific move One specific move. How this move is chosen depends upon on the move being used.
3 2 9 Selected Pokémon One other Pokémon on the field, selected by the trainer. Stolen moves reuse the same target.
4 3 9 Ally The user's ally (if any).

View file

@ -1,4 +1,4 @@
nature_id,language_id,name nature_id,local_language_id,name
1,1,がんばりや 1,1,がんばりや
1,5,Hardi 1,5,Hardi
1,6,Robust 1,6,Robust
1 nature_id language_id local_language_id name
2 1 1 がんばりや
3 1 5 Hardi
4 1 6 Robust

View file

@ -1,4 +1,4 @@
pokeathlon_stat_id,language_id,name pokeathlon_stat_id,local_language_id,name
1,9,Speed 1,9,Speed
2,9,Power 2,9,Power
3,9,Skill 3,9,Skill
1 pokeathlon_stat_id language_id local_language_id name
2 1 9 9 Speed
3 2 9 9 Power
4 3 9 9 Skill

View file

@ -1,4 +1,4 @@
pokedex_id,language_id,name,description pokedex_id,local_language_id,name,description
1,9,National,Entire National dex 1,9,National,Entire National dex
2,9,Kanto,Red/Blue/Yellow Kanto dex 2,9,Kanto,Red/Blue/Yellow Kanto dex
3,9,Original Johto,"Gold/Silver/Crystal Johto dex—called the ""New"" Pokédex in-game" 3,9,Original Johto,"Gold/Silver/Crystal Johto dex—called the ""New"" Pokédex in-game"

1 pokedex_id language_id local_language_id name description
2 1 9 National Entire National dex
3 2 9 Kanto Red/Blue/Yellow Kanto dex
4 3 9 Original Johto Gold/Silver/Crystal Johto dex—called the "New" Pokédex in-game

View file

@ -1,4 +1,4 @@
pokemon_color_id,language_id,name pokemon_color_id,local_language_id,name
1,9,Black 1,9,Black
2,9,Blue 2,9,Blue
3,9,Brown 3,9,Brown
1 pokemon_color_id language_id local_language_id name
2 1 9 Black
3 2 9 Blue
4 3 9 Brown

View file

@ -1,4 +1,4 @@
pokemon_form_group_id,language_id,term,description pokemon_form_group_id,local_language_id,term,description
172,9,,"Spiky-eared Pichu can only be received by taking the shiny Pichu from an official promotion to [Celebi]{pokemon}'s shrine in [Ilex Forest]{location}. Spiky-eared Pichu is always female, cannot evolve, and cannot be taken into the Wi-Fi Club or the Union Room, but is otherwise a normal Pichu." 172,9,,"Spiky-eared Pichu can only be received by taking the shiny Pichu from an official promotion to [Celebi]{pokemon}'s shrine in [Ilex Forest]{location}. Spiky-eared Pichu is always female, cannot evolve, and cannot be taken into the Wi-Fi Club or the Union Room, but is otherwise a normal Pichu."
201,9,,Forms only affect appearance. A form is determined at random before a wild encounter and cannot be changed. 201,9,,Forms only affect appearance. A form is determined at random before a wild encounter and cannot be changed.
351,9,Form,"Form changes along with type to match the [weather]{mechanic} in battle, due to [Forecast]{ability}. Castform is always in its normal form outside of battle, regardless of weather." 351,9,Form,"Form changes along with type to match the [weather]{mechanic} in battle, due to [Forecast]{ability}. Castform is always in its normal form outside of battle, regardless of weather."

1 pokemon_form_group_id language_id local_language_id term description
2 172 9 Spiky-eared Pichu can only be received by taking the shiny Pichu from an official promotion to [Celebi]{pokemon}'s shrine in [Ilex Forest]{location}. Spiky-eared Pichu is always female, cannot evolve, and cannot be taken into the Wi-Fi Club or the Union Room, but is otherwise a normal Pichu.
3 201 9 Forms only affect appearance. A form is determined at random before a wild encounter and cannot be changed.
4 351 9 Form Form changes along with type to match the [weather]{mechanic} in battle, due to [Forecast]{ability}. Castform is always in its normal form outside of battle, regardless of weather.

View file

@ -1,4 +1,4 @@
pokemon_form_id,language_id,name pokemon_form_id,local_language_id,name
1,9, 1,9,
2,9, 2,9,
3,9, 3,9,
1 pokemon_form_id language_id local_language_id name
2 1 9
3 2 9
4 3 9

View file

@ -1,4 +1,4 @@
pokemon_id,generation_id,internal_id pokemon_id,generation_id,game_index
1,1,153 1,1,153
1,2,1 1,2,1
1,3,1 1,3,1
1 pokemon_id generation_id internal_id game_index
2 1 1 153
3 1 2 1
4 1 3 1

View file

@ -1,4 +1,4 @@
pokemon_habitat_id,language_id,name pokemon_habitat_id,local_language_id,name
1,9,cave 1,9,cave
2,9,forest 2,9,forest
3,9,grassland 3,9,grassland
1 pokemon_habitat_id language_id local_language_id name
2 1 9 cave
3 2 9 forest
4 3 9 grassland

View file

@ -1,4 +1,4 @@
pokemon_move_method_id,language_id,name,description pokemon_move_method_id,local_language_id,name,description
1,9,Level up,Learned when a Pokémon reaches a certain level. 1,9,Level up,Learned when a Pokémon reaches a certain level.
2,9,Egg,"Appears on a newly-hatched Pokémon, if the father had the same move." 2,9,Egg,"Appears on a newly-hatched Pokémon, if the father had the same move."
3,9,Tutor,Can be taught at any time by an NPC. 3,9,Tutor,Can be taught at any time by an NPC.

1 pokemon_move_method_id language_id local_language_id name description
2 1 9 Level up Learned when a Pokémon reaches a certain level.
3 2 9 Egg Appears on a newly-hatched Pokémon, if the father had the same move.
4 3 9 Tutor Can be taught at any time by an NPC.

View file

@ -1,4 +1,4 @@
pokemon_id,language_id,name,species pokemon_id,local_language_id,name,species
1,1,フシギダネ, 1,1,フシギダネ,
1,2,Fushigidane, 1,2,Fushigidane,
1,3,이상해씨, 1,3,이상해씨,
1 pokemon_id language_id local_language_id name species
2 1 1 フシギダネ
3 1 2 Fushigidane
4 1 3 이상해씨

View file

@ -1,4 +1,4 @@
pokemon_shape_id,language_id,name,awesome_name pokemon_shape_id,local_language_id,name,awesome_name
1,9,Ball,Pomaceous 1,9,Ball,Pomaceous
2,9,Squiggle,Caudal 2,9,Squiggle,Caudal
3,9,Fish,Ichthyic 3,9,Fish,Ichthyic

1 pokemon_shape_id language_id local_language_id name awesome_name
2 1 9 Ball Pomaceous
3 2 9 Squiggle Caudal
4 3 9 Fish Ichthyic

View file

@ -1,4 +1,4 @@
region_id,language_id,name region_id,local_language_id,name
1,9,Kanto 1,9,Kanto
2,9,Johto 2,9,Johto
3,9,Hoenn 3,9,Hoenn
1 region_id language_id local_language_id name
2 1 9 9 Kanto
3 2 9 9 Johto
4 3 9 9 Hoenn

View file

@ -1,4 +1,4 @@
stat_hint_id,language_id,message stat_hint_id,local_language_id,message
1,9,Loves to eat 1,9,Loves to eat
2,9,Proud of its power 2,9,Proud of its power
3,9,Sturdy body 3,9,Sturdy body
1 stat_hint_id language_id local_language_id message
2 1 9 Loves to eat
3 2 9 Proud of its power
4 3 9 Sturdy body

View file

@ -1,4 +1,4 @@
stat_id,language_id,name stat_id,local_language_id,name
1,9,HP 1,9,HP
2,9,Attack 2,9,Attack
3,9,Defense 3,9,Defense
1 stat_id language_id local_language_id name
2 1 9 HP
3 2 9 Attack
4 3 9 Defense

View file

@ -1,4 +1,4 @@
super_contest_effect_id,language_id,flavor_text super_contest_effect_id,local_language_id,flavor_text
1,9,Enables the user to perform first in the next turn. 1,9,Enables the user to perform first in the next turn.
2,9,Enables the user to perform last in the next turn. 2,9,Enables the user to perform last in the next turn.
4,9,Earn +2 if the Judge's Voltage goes up. 4,9,Earn +2 if the Judge's Voltage goes up.

1 super_contest_effect_id language_id local_language_id flavor_text
2 1 9 Enables the user to perform first in the next turn.
3 2 9 Enables the user to perform last in the next turn.
4 4 9 Earn +2 if the Judge's Voltage goes up.

View file

@ -1,4 +1,4 @@
type_id,language_id,name type_id,local_language_id,name
1,1,ノーマル 1,1,ノーマル
1,5,Normal 1,5,Normal
1,6,Normal 1,6,Normal
1 type_id language_id local_language_id name
2 1 1 ノーマル
3 1 5 Normal
4 1 6 Normal

View file

@ -1,4 +1,4 @@
version_id,language_id,name version_id,local_language_id,name
1,9,Red 1,9,Red
2,9,Blue 2,9,Blue
3,9,Yellow 3,9,Yellow
1 version_id language_id local_language_id name
2 1 9 Red
3 2 9 Blue
4 3 9 Yellow

View file

@ -2,6 +2,7 @@ from sqlalchemy import MetaData, Table, engine_from_config, orm
from ..defaults import get_default_db_uri from ..defaults import get_default_db_uri
from .tables import metadata from .tables import metadata
from .multilang import MultilangSession
def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''): def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''):
@ -40,7 +41,7 @@ def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''):
all_session_args = dict(autoflush=True, autocommit=False, bind=engine) all_session_args = dict(autoflush=True, autocommit=False, bind=engine)
all_session_args.update(session_args) all_session_args.update(session_args)
sm = orm.sessionmaker(**all_session_args) sm = orm.sessionmaker(class_=MultilangSession, **all_session_args)
session = orm.scoped_session(sm) session = orm.scoped_session(sm)
return session return session

View file

@ -56,34 +56,25 @@ class MarkdownString(object):
""" """
return self.source_text return self.source_text
def _markdownify_effect_text(move, effect_text):
class _MoveEffects(object):
def __init__(self, effect_column, move):
self.effect_column = effect_column
self.move = move
def __contains__(self, lang):
return lang in self.move.move_effect.prose
def __getitem__(self, lang):
try:
effect_text = getattr(self.move.move_effect.prose[lang], self.effect_column)
except AttributeError:
return None
effect_text = effect_text.replace( effect_text = effect_text.replace(
u'$effect_chance', u'$effect_chance',
unicode(self.move.effect_chance), unicode(move.effect_chance),
) )
return MarkdownString(effect_text) return MarkdownString(effect_text)
class MoveEffectsProperty(object): class MoveEffectProperty(object):
"""Property that wraps move effects. Used like this: """Property that wraps move effects. Used like this:
MoveClass.effects = MoveEffectProperty('effect') MoveClass.effect = MoveEffectProperty('effect')
some_move.effects[lang] # returns a MarkdownString some_move.effect # returns a MarkdownString
some_move.effects[lang].as_html # returns a chunk of HTML some_move.effect.as_html # returns a chunk of HTML
This class attempts to detect if the wrapped property is a dict-based
association proxy, and will act like such a dict if so. Don't rely on it
for querying, of course.
This class also performs simple substitution on the effect, replacing This class also performs simple substitution on the effect, replacing
`$effect_chance` with the move's actual effect chance. `$effect_chance` with the move's actual effect chance.
@ -92,8 +83,17 @@ class MoveEffectsProperty(object):
def __init__(self, effect_column): def __init__(self, effect_column):
self.effect_column = effect_column self.effect_column = effect_column
def __get__(self, move, move_class): def __get__(self, obj, cls):
return _MoveEffects(self.effect_column, move) prop = getattr(obj.move_effect, self.effect_column)
if isinstance(prop, dict):
# Looks like a dict proxy; markdownify everyone
newdict = dict(prop)
for key in newdict:
newdict[key] = _markdownify_effect_text(obj, newdict[key])
return newdict
# Otherwise, scalar prop. Boring
return _markdownify_effect_text(obj, prop)
class MarkdownColumn(sqlalchemy.types.TypeDecorator): class MarkdownColumn(sqlalchemy.types.TypeDecorator):
"""Generic SQLAlchemy column type for Markdown text. """Generic SQLAlchemy column type for Markdown text.

164
pokedex/db/multilang.py Normal file
View file

@ -0,0 +1,164 @@
from functools import partial
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm import aliased, compile_mappers, mapper, relationship, synonym
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.orm.session import Session, object_session
from sqlalchemy.schema import Column, ForeignKey, Table
from sqlalchemy.sql.expression import and_, bindparam, select
from sqlalchemy.types import Integer
def create_translation_table(_table_name, foreign_class, relation_name,
language_class, **kwargs):
"""Creates a table that represents some kind of data attached to the given
foreign class, but translated across several languages. Returns the new
table's mapped class. It won't be declarative, but it will have a
`__table__` attribute so you can retrieve the Table object.
`foreign_class` must have a `__singlename__`, currently only used to create
the name of the foreign key column.
Also supports the notion of a default language, which is attached to the
session. This is English by default, for historical and practical reasons.
Usage looks like this:
class Foo(Base): ...
create_translation_table('foo_bars', Foo, 'bars',
name = Column(...),
)
# Now you can do the following:
foo.name
foo.name_map['en']
foo.foo_bars['en']
foo.name_map['en'] = "new name"
del foo.name_map['en']
q.options(joinedload(Foo.bars_local))
q.options(joinedload(Foo.bars))
The following properties are added to the passed class:
- `(relation_name)`, a relation to the new table. It uses a dict-based
collection class, where the keys are language identifiers and the values
are rows in the created tables.
- `(relation_name)_local`, a relation to the row in the new table that
matches the current default language.
- `(relation_name)_class`, the class created by this function.
Note that these are distinct relations. Even though the former necessarily
includes the latter, SQLAlchemy doesn't treat them as linked; loading one
will not load the other. Modifying both within the same transaction has
undefined behavior.
For each column provided, the following additional attributes are added to
Foo:
- `(column)_map`, an association proxy onto `foo_bars`.
- `(column)`, an association proxy onto `foo_bars_local`.
Pardon the naming disparity, but the grammar suffers otherwise.
Modifying these directly is not likely to be a good idea.
"""
# n.b.: language_class only exists for the sake of tests, which sometimes
# want to create tables entirely separate from the pokedex metadata
foreign_key_name = foreign_class.__singlename__ + '_id'
Translations = type(_table_name, (object,), {
'_language_identifier': association_proxy('local_language', 'identifier'),
})
# Create the table object
table = Table(_table_name, foreign_class.__table__.metadata,
Column(foreign_key_name, Integer, ForeignKey(foreign_class.id),
primary_key=True, nullable=False),
Column('local_language_id', Integer, ForeignKey(language_class.id),
primary_key=True, nullable=False),
)
Translations.__table__ = table
# Add ye columns
# Column objects have a _creation_order attribute in ascending order; use
# this to get the (unordered) kwargs sorted correctly
kwitems = kwargs.items()
kwitems.sort(key=lambda kv: kv[1]._creation_order)
for name, column in kwitems:
column.name = name
table.append_column(column)
# Construct ye mapper
mapper(Translations, table, properties={
'foreign_id': synonym(foreign_key_name),
'local_language': relationship(language_class,
primaryjoin=table.c.local_language_id == language_class.id,
lazy='joined',
innerjoin=True),
})
# Add full-table relations to the original class
# Foo.bars_table
setattr(foreign_class, relation_name + '_table', Translations)
# Foo.bars
setattr(foreign_class, relation_name, relationship(Translations,
primaryjoin=foreign_class.id == Translations.foreign_id,
collection_class=attribute_mapped_collection('local_language'),
# TODO
lazy='select',
))
# Foo.bars_local
# This is a bit clever; it uses bindparam() to make the join clause
# modifiable on the fly. db sessions know the current language identifier
# populates the bindparam. The manual alias and join are (a) to make the
# condition nice (sqla prefers an EXISTS) and to make the columns play nice
# when foreign_class == language_class.
local_relation_name = relation_name + '_local'
language_class_a = aliased(language_class)
setattr(foreign_class, local_relation_name, relationship(Translations,
primaryjoin=and_(
foreign_class.id == Translations.foreign_id,
Translations.local_language_id == select(
[language_class_a.id],
language_class_a.identifier ==
bindparam('_default_language', required=True),
),
),
uselist=False,
# TODO MORESO HERE
lazy='select',
))
# Add per-column proxies to the original class
for name, column in kwitems:
# Class.(column) -- accessor for the default language's value
setattr(foreign_class, name,
association_proxy(local_relation_name, name))
# Class.(column)_map -- accessor for the language dict
# Need a custom creator since Translations doesn't have an init, and
# these are passed as *args anyway
def creator(language, value):
row = Translations()
row.local_language = language
setattr(row, name, value)
return row
setattr(foreign_class, name + '_map',
association_proxy(relation_name, name, creator=creator))
# Done
return Translations
class MultilangSession(Session):
"""A tiny Session subclass that adds support for a default language."""
default_language = 'en'
def execute(self, clause, params=None, *args, **kwargs):
if not params:
params = {}
params.setdefault('_default_language', self.default_language)
return super(MultilangSession, self).execute(
clause, params, *args, **kwargs)

File diff suppressed because it is too large Load diff

View file

@ -225,7 +225,7 @@ class PokedexLookup(object):
# Some things also have other languages' names # Some things also have other languages' names
# XXX other language form names..? # XXX other language form names..?
seen = set() seen = set()
for language, name in getattr(row, 'names', []).items(): for language, name in getattr(row, 'name_map', {}).items():
if name in seen: if name in seen:
# Don't add the name again as a different # Don't add the name again as a different
# language; no point and it makes spell results # language; no point and it makes spell results

View file

@ -128,8 +128,8 @@ class SaveFilePokemon(object):
self._held_item = None self._held_item = None
if st.held_item_id: if st.held_item_id:
self._held_item = session.query(tables.ItemInternalID) \ self._held_item = session.query(tables.ItemGameIndex) \
.filter_by(generation_id = 4, internal_id = st.held_item_id).one().item .filter_by(generation_id = 4, game_index = st.held_item_id).one().item
self._stats = [] self._stats = []
for pokemon_stat in self._pokemon.stats: for pokemon_stat in self._pokemon.stats:
@ -173,19 +173,19 @@ class SaveFilePokemon(object):
pokeball_id = st.hgss_pokeball - 17 + 492 pokeball_id = st.hgss_pokeball - 17 + 492
else: else:
pokeball_id = st.dppt_pokeball pokeball_id = st.dppt_pokeball
self._pokeball = session.query(tables.ItemInternalID) \ self._pokeball = session.query(tables.ItemGameIndex) \
.filter_by(generation_id = 4, internal_id = pokeball_id).one().item .filter_by(generation_id = 4, game_index = pokeball_id).one().item
egg_loc_id = st.pt_egg_location_id or st.dp_egg_location_id egg_loc_id = st.pt_egg_location_id or st.dp_egg_location_id
met_loc_id = st.pt_met_location_id or st.dp_met_location_id met_loc_id = st.pt_met_location_id or st.dp_met_location_id
self._egg_location = None self._egg_location = None
if egg_loc_id: if egg_loc_id:
self._egg_location = session.query(tables.LocationInternalID) \ self._egg_location = session.query(tables.LocationGameIndex) \
.filter_by(generation_id = 4, internal_id = egg_loc_id).one().location .filter_by(generation_id = 4, game_index = egg_loc_id).one().location
self._met_location = session.query(tables.LocationInternalID) \ self._met_location = session.query(tables.LocationGameIndex) \
.filter_by(generation_id = 4, internal_id = met_loc_id).one().location .filter_by(generation_id = 4, game_index = met_loc_id).one().location
@property @property
def species(self): def species(self):

View file

@ -1,9 +1,13 @@
# encoding: utf8 # encoding: utf8
from nose.tools import * from nose.tools import *
import unittest import unittest
from sqlalchemy.orm import class_mapper from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import class_mapper, joinedload, sessionmaker
from sqlalchemy.orm.session import Session
from sqlalchemy.ext.declarative import declarative_base
from pokedex.db import tables, markdown from pokedex.db import tables, markdown
from pokedex.db.multilang import create_translation_table
def test_variable_names(): def test_variable_names():
"""We want pokedex.db.tables to export tables using the class name""" """We want pokedex.db.tables to export tables using the class name"""
@ -22,6 +26,126 @@ def test_variable_names():
for table in tables.table_classes: for table in tables.table_classes:
assert getattr(tables, table.__name__) is table assert getattr(tables, table.__name__) is table
def test_i18n_table_creation():
"""Creates and manipulates a magical i18n table, completely independent of
the existing schema and data. Makes sure that the expected behavior of the
various proxies and columns works.
"""
Base = declarative_base()
engine = create_engine("sqlite:///:memory:", echo=True)
Base.metadata.bind = engine
# Need this for the foreign keys to work!
class Language(Base):
__tablename__ = 'languages'
id = Column(Integer, primary_key=True, nullable=False)
identifier = Column(String(2), nullable=False, unique=True)
class Foo(Base):
__tablename__ = 'foos'
__singlename__ = 'foo'
id = Column(Integer, primary_key=True, nullable=False)
FooText = create_translation_table('foo_text', Foo,
language_class=Language,
name = Column(String(100)),
)
class FauxSession(Session):
def execute(self, clause, params=None, *args, **kwargs):
if not params:
params = {}
params.setdefault('_default_language', 'en')
return super(FauxSession, self).execute(clause, params, *args, **kwargs)
# OK, create all the tables and gimme a session
Base.metadata.create_all()
sess = sessionmaker(engine, class_=FauxSession)()
# Create some languages and foos to bind together
lang_en = Language(identifier='en')
sess.add(lang_en)
lang_jp = Language(identifier='jp')
sess.add(lang_jp)
lang_ru = Language(identifier='ru')
sess.add(lang_ru)
foo = Foo()
sess.add(foo)
# Commit so the above get primary keys filled in
sess.commit()
# Give our foo some names, as directly as possible
foo_text = FooText()
foo_text.object_id = foo.id
foo_text.language_id = lang_en.id
foo_text.name = 'english'
sess.add(foo_text)
foo_text = FooText()
foo_text.object_id = foo.id
foo_text.language_id = lang_jp.id
foo_text.name = 'nihongo'
sess.add(foo_text)
# Commit! This will expire all of the above.
sess.commit()
### Test 1: re-fetch foo and check its attributes
foo = sess.query(Foo).params(_default_language='en').one()
# Dictionary of language identifiers => names
assert foo.name_map[lang_en] == 'english'
assert foo.name_map[lang_jp] == 'nihongo'
# Default language, currently English
assert foo.name == 'english'
sess.expire_all()
### Test 2: querying by default language name should work
foo = sess.query(Foo).filter_by(name='english').one()
assert foo.name == 'english'
sess.expire_all()
### Test 3: joinedload on the default name should appear to work
# THIS SHOULD WORK SOMEDAY
# .options(joinedload(Foo.name)) \
foo = sess.query(Foo) \
.options(joinedload(Foo.foo_text_local)) \
.one()
assert foo.name == 'english'
sess.expire_all()
### Test 4: joinedload on all the names should appear to work
# THIS SHOULD ALSO WORK SOMEDAY
# .options(joinedload(Foo.name_map)) \
foo = sess.query(Foo) \
.options(joinedload(Foo.foo_text)) \
.one()
assert foo.name_map[lang_en] == 'english'
assert foo.name_map[lang_jp] == 'nihongo'
sess.expire_all()
### Test 5: Mutating the dict collection should work
foo = sess.query(Foo).one()
foo.name_map[lang_en] = 'different english'
foo.name_map[lang_ru] = 'new russian'
sess.commit()
assert foo.name_map[lang_en] == 'different english'
assert foo.name_map[lang_ru] == 'new russian'
def test_texts(): def test_texts():
"""Check DB schema for integrity of text columns & translations. """Check DB schema for integrity of text columns & translations.