@@ 1,8 1,9 @@
+use std::collections::HashMap;
use std::{env, fs::File};
use std::io::{prelude::*, BufReader, BufWriter};
use minicbor::bytes::ByteArray;
use minicbor_io::Writer;
-use pokemon::pokedex::{self, Pokemon, Type, Stats};
+use pokemon::pokedex::{self, Pokemon, Type, StatData, MoveListChunk, Move, LearnableMove, LearnCondition};
use serde_json::Value;
fn main() {
@@ 22,18 23,94 @@ fn main() {
let json_file = File::open(format!("{}.json", args[1])).unwrap();
let json: Value = serde_json::from_reader(BufReader::new(json_file)).unwrap();
- let pokemon = parse_pokemon(json, &buffer).unwrap();
-
+ let pokemon = parse_pokemon(&json, &buffer).unwrap();
println!("created pokemon {:?}", pokemon);
+ let move_list = parse_movelist(&json["moves"]).unwrap();
+ println!("created movelist {:?}", move_list);
let output_file = BufWriter::new(File::create(&args[2]).unwrap());
let mut cbor_writer = Writer::new(output_file);
- let outsize = cbor_writer.write(pokemon).unwrap();
+ let mut outsize = cbor_writer.write(pokemon).unwrap();
+ outsize += cbor_writer.write(move_list).unwrap();
println!("wrote to file. final size was {} bytes", outsize);
}
-fn parse_pokemon(json: Value, bitmap: &[u8; 578]) -> Result<Pokemon, &'static str> {
+fn parse_movelist(json: &Value) -> Result<Vec<MoveListChunk>, &'static str> {
+ let mut all_chunks = Vec::new();
+ let mut current_chunk: [Option<LearnableMove>; 16] = [None; 16];
+ let mut current_chunk_i = 0;
+ for m in json.as_array().unwrap_or(&Vec::new()) {
+ let parsed = match parse_learnable_move(m) {
+ Ok(p) => p,
+ Err(e) => return Err(e)
+ };
+ for i in parsed {
+ if current_chunk_i == 16 {
+ all_chunks.push(MoveListChunk{
+ is_final_chunk: false,
+ moves: current_chunk
+ });
+ current_chunk = [None; 16];
+ current_chunk_i = 0;
+ }
+
+ current_chunk[current_chunk_i] = Some(i);
+ current_chunk_i += 1;
+ }
+ }
+
+ // Double check that we actually got results
+ if current_chunk_i == 0 && all_chunks.len() == 0 {
+ return Err("found no moves");
+ }
+
+ // Finish the final chunk.
+ all_chunks.push(MoveListChunk{
+ is_final_chunk: true,
+ moves: current_chunk
+ });
+
+ return Ok(all_chunks);
+}
+
+fn parse_learnable_move(json: &Value) -> Result<Vec<LearnableMove>, &'static str> {
+ let parts: Vec<&str> = match json["move"]["url"].as_str() {
+ Some(i) => i.split("/").collect(),
+ None => return Err("move missing id")
+ };
+ let id: u16 = match parts[parts.len() - 2].parse() {
+ Ok(i) => i,
+ Err(_) => return Err("failed to parse id")
+ };
+ let mut moves = Vec::new();
+ for method in json["version_group_details"].as_array().unwrap_or(&Vec::new()) {
+ moves.push(LearnableMove{
+ id,
+ condition: match method["move_learn_method"].as_str() {
+ Some("level-up") => LearnCondition::LevelUp{
+ level: match method["level_learned_at"].as_u64().map(|i| u8::try_from(i).ok()).flatten() {
+ Some(l) => l,
+ None => return Err("failed to parse level up method")
+ }
+ },
+ Some("machine") => LearnCondition::Machine,
+ Some(_) => return Err("unknown learn method"),
+ None => return Err("missing learn method")
+ }
+ })
+ }
+ return match moves.len() {
+ 0 => Err("move with no learn methods"),
+ _ => Ok(moves)
+ }
+}
+
+fn parse_move(json: Value) -> Result<Move, &'static str> {
+ return Err("uh oh");
+}
+
+fn parse_pokemon(json: &Value, bitmap: &[u8; 578]) -> Result<Pokemon, &'static str> {
let name = match json["name"].as_str() {
Some(n) => {
let mut i = 0;
@@ 71,8 148,8 @@ fn parse_pokemon(json: Value, bitmap: &[u8; 578]) -> Result<Pokemon, &'static st
None => return Err("no types found")
}
- let stats = match json["stats"].as_array() {
- Some(all_stats) => all_stats.iter().flat_map(|j| parse_as_stats(j)).collect(),
+ let stats: HashMap<_, _> = match json["stats"].as_array() {
+ Some(all_stats) => all_stats.iter().flat_map(|j| parse_as_stat_data(j)).collect(),
None => return Err("missing stats")
};
@@ 95,7 172,12 @@ fn parse_pokemon(json: Value, bitmap: &[u8; 578]) -> Result<Pokemon, &'static st
Some(i) => i,
None => return Err("missing base experience")
},
- stats,
+ hp: stats["hp"],
+ attack: stats["attack"],
+ defense: stats["defense"],
+ special_attack: stats["special-attack"],
+ special_defense: stats["special-defense"],
+ speed: stats["speed"],
sprite: ByteArray::from(*bitmap),
})
}
@@ 112,25 194,23 @@ fn parse_as_u8(json: &Value) -> Option<u8> {
}
}
-fn parse_as_stats(json: &Value) -> Option<Stats> {
- Some(Stats {
- stat: match json["stat"].as_str() {
- Some(s) => match s {
- "hp" => Stat::Hp,
- "attack" => Stat::Attack,
- "defense" => Stat::Defense,
- "special-attack" => Stat::SpecialAttack,
- "special-defense" => Stat::SpecialDefense,
- "speed" => Stat::Speed,
- _ => return None
- }
- None => return None
- },
- base_value: match json["base_state"] {
+fn parse_as_stat_data(json: &Value) -> Option<(&str, StatData)> {
+ Some((
+ match json["stat"].as_str() {
Some(i) => i,
None => return None
- }
- })
+ },
+ StatData {
+ base_value: match json["base_stat"].as_u64().map(|i| u16::try_from(i)) {
+ Some(i) => {
+ match i {
+ Ok(i) => i,
+ Err(_) => return None
+ }
+ },
+ None => return None
+ }
+ }))
}
fn type_from_string(s: &str) -> Result<Type, &str> {
@@ 12,9 12,15 @@ pub mod pokedex {
#[n(4)] pub capture_rate: u8,
#[n(5)] pub base_experience: u8,
- #[n(6)] pub stats: [Stats; 6],
- #[b(7)] pub sprite: ByteArray<578>,
+ #[n(7)] pub hp: StatData,
+ #[n(8)] pub attack: StatData,
+ #[n(9)] pub defense: StatData,
+ #[n(10)] pub special_attack: StatData,
+ #[n(11)] pub special_defense: StatData,
+ #[n(12)] pub speed: StatData,
+
+ #[b(13)] pub sprite: ByteArray<578>,
}
#[derive(Encode, Decode, Debug)]
@@ 28,10 34,9 @@ pub mod pokedex {
#[n(5)] Speed,
}
- #[derive(Encode, Decode, Debug)]
- pub struct Stats {
- #[n(0)] stat: Stat,
- #[n(1)] base_value: u16,
+ #[derive(Encode, Decode, Debug, Clone, Copy)]
+ pub struct StatData {
+ #[n(1)] pub base_value: u16,
}
// These could be created dynamically from the JSON data. This isn't so bad
@@ 61,17 66,17 @@ pub mod pokedex {
#[derive(Encode, Decode, Debug)]
pub struct MoveListChunk {
- #[n(0)] is_final_chunk: bool,
- #[n(1)] moves: [Option<LearnableMove>; 16],
+ #[n(0)] pub is_final_chunk: bool,
+ #[n(1)] pub moves: [Option<LearnableMove>; 16],
}
- #[derive(Encode, Decode, Debug)]
+ #[derive(Encode, Decode, Debug, Copy, Clone)]
pub struct LearnableMove {
- #[n(0)] id: u16,
- #[n(1)] condition: LearnCondition,
+ #[n(0)] pub id: u16,
+ #[n(1)] pub condition: LearnCondition,
}
- #[derive(Encode, Decode, Debug)]
+ #[derive(Encode, Decode, Debug, Copy, Clone)]
pub enum LearnCondition {
#[n(0)] LevelUp {
#[n(0)] level: u8
@@ 81,39 86,39 @@ pub mod pokedex {
#[derive(Encode, Decode, Debug)]
pub struct Move {
- #[n(0)] id: u16,
- #[n(1)] name: [char; 12],
+ #[n(0)] pub id: u16,
+ #[n(1)] pub name: [char; 12],
- #[n(2)] type_: Type,
- #[n(3)] damage_class: DamageClass,
- #[n(4)] target: Target,
+ #[n(2)] pub type_: Type,
+ #[n(3)] pub damage_class: DamageClass,
+ #[n(4)] pub target: Target,
- #[n(5)] accuracy: u8,
- #[n(6)] power: u8,
- #[n(7)] pp: u8,
- #[n(8)] priority: u8,
+ #[n(5)] pub accuracy: u8,
+ #[n(6)] pub power: u8,
+ #[n(7)] pub pp: u8,
+ #[n(8)] pub priority: u8,
- #[n(9)] parameters: Parameters,
- #[n(10)] stat_changes: [Option<StatChange>; 2]
+ #[n(9)] pub parameters: Parameters,
+ #[n(10)] pub stat_changes: [Option<StatChange>; 2]
}
#[derive(Encode, Decode, Debug)]
#[cbor(map)]
pub struct Parameters {
- #[n(0)] ailment: Option<AilmentParameter>,
- #[n(1)] crit_rate: u8,
- #[n(2)] drain: u8,
- #[n(3)] flinch_chance: u8,
- #[n(4)] healing: u8,
- #[n(5)] stat_chance: u8,
- #[n(6)] turn_range: Option<ParameterRange>,
- #[n(7)] hit_range: Option<ParameterRange>,
+ #[n(0)] pub ailment: Option<AilmentParameter>,
+ #[n(1)] pub crit_rate: u8,
+ #[n(2)] pub drain: u8,
+ #[n(3)] pub flinch_chance: u8,
+ #[n(4)] pub healing: u8,
+ #[n(5)] pub stat_chance: u8,
+ #[n(6)] pub turn_range: Option<ParameterRange>,
+ #[n(7)] pub hit_range: Option<ParameterRange>,
}
#[derive(Encode, Decode, Debug)]
pub struct AilmentParameter {
- #[n(0)] ailment: AilmentType,
- #[n(1)] chance: u8,
+ #[n(0)] pub ailment: AilmentType,
+ #[n(1)] pub chance: u8,
}
#[derive(Encode, Decode, Debug)]
@@ 132,8 137,8 @@ pub mod pokedex {
#[derive(Encode, Decode, Debug)]
pub struct ParameterRange {
- #[n(0)] min: u8,
- #[n(1)] max: u8,
+ #[n(0)] pub min: u8,
+ #[n(1)] pub max: u8,
}
#[derive(Encode, Decode, Debug)]
@@ 159,7 164,7 @@ pub mod pokedex {
#[derive(Encode, Decode, Debug)]
pub struct StatChange {
- #[n(0)] amount: u8,
- #[n(1)] stat: Stat,
+ #[n(0)] pub amount: u8,
+ #[n(1)] pub stat: Stat,
}
}