~jacqueline/pokemon

e663ccdb5c6e0769e7590cde4d12bf22bd677ff8 — jacqueline leykam 1 year, 2 months ago ee3373a
Write a complete pokemon to a file!
2 files changed, 147 insertions(+), 62 deletions(-)

M src/bin/pack-resources.rs
M src/lib.rs
M src/bin/pack-resources.rs => src/bin/pack-resources.rs +105 -25
@@ 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> {

M src/lib.rs => src/lib.rs +42 -37
@@ 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,
    }
}