added ability info
parent
b071b55a58
commit
a8fd4e8ba1
File diff suppressed because it is too large
Load Diff
|
|
@ -7,10 +7,7 @@ use std::{
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use json::JsonValue;
|
use json::JsonValue;
|
||||||
|
|
||||||
use crate::{
|
use crate::{json::*, pokemon::*};
|
||||||
json::{read_characteristics, read_natures, read_pokedex},
|
|
||||||
pokemon::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct DatabasePlugin;
|
pub struct DatabasePlugin;
|
||||||
|
|
||||||
|
|
@ -19,6 +16,7 @@ impl Plugin for DatabasePlugin {
|
||||||
app.insert_resource(Database::<Pokemon>::default())
|
app.insert_resource(Database::<Pokemon>::default())
|
||||||
.insert_resource(Database::<Nature>::default())
|
.insert_resource(Database::<Nature>::default())
|
||||||
.insert_resource(Database::<Characteristic>::default())
|
.insert_resource(Database::<Characteristic>::default())
|
||||||
|
.insert_resource(Database::<Ability>::default())
|
||||||
.add_startup_system(database_setup);
|
.add_startup_system(database_setup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -46,9 +44,11 @@ where
|
||||||
|
|
||||||
fn database_setup(
|
fn database_setup(
|
||||||
mut pokemon_database: ResMut<Database<Pokemon>>,
|
mut pokemon_database: ResMut<Database<Pokemon>>,
|
||||||
|
mut ability_database: ResMut<Database<Ability>>,
|
||||||
mut nature_database: ResMut<Database<Nature>>,
|
mut nature_database: ResMut<Database<Nature>>,
|
||||||
mut characteristic_database: ResMut<Database<Characteristic>>,
|
mut characteristic_database: ResMut<Database<Characteristic>>,
|
||||||
) {
|
) {
|
||||||
|
ability_database.populate_from_json(&read_abilities());
|
||||||
nature_database.populate_from_json(&read_natures());
|
nature_database.populate_from_json(&read_natures());
|
||||||
pokemon_database.populate_from_json(&read_pokedex());
|
pokemon_database.populate_from_json(&read_pokedex());
|
||||||
characteristic_database.populate_from_json(&read_characteristics());
|
characteristic_database.populate_from_json(&read_characteristics());
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::inspector::{Battle, PokemonInstance};
|
use super::inspector::{Battle, ParsedPokemonInstance};
|
||||||
use crate::pokemon::*;
|
use crate::pokemon::*;
|
||||||
|
|
||||||
const PLAYER_PARTY_OFFSET: usize = 0x21E42C;
|
const PLAYER_PARTY_OFFSET: usize = 0x21E42C;
|
||||||
|
|
@ -29,7 +29,7 @@ struct Header {
|
||||||
checksum: u16,
|
checksum: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_battle_party(data: &Vec<u8>) -> Result<Battle, String> {
|
pub fn parse_battle_party(data: &Vec<u8>) -> Result<Battle<ParsedPokemonInstance>, String> {
|
||||||
let mut battle = Battle::default();
|
let mut battle = Battle::default();
|
||||||
for i in 0..PARTY_MAX_SIZE {
|
for i in 0..PARTY_MAX_SIZE {
|
||||||
if let Some(instance) = try_parse(data, PLAYER_PARTY_OFFSET + i * POKEMON_SIZE) {
|
if let Some(instance) = try_parse(data, PLAYER_PARTY_OFFSET + i * POKEMON_SIZE) {
|
||||||
|
|
@ -42,13 +42,13 @@ pub fn parse_battle_party(data: &Vec<u8>) -> Result<Battle, String> {
|
||||||
Ok(battle)
|
Ok(battle)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_parse(data: &[u8], offset: usize) -> Option<PokemonInstance> {
|
fn try_parse(data: &[u8], offset: usize) -> Option<ParsedPokemonInstance> {
|
||||||
let encrypted = &data[offset..offset + POKEMON_SIZE];
|
let encrypted = &data[offset..offset + POKEMON_SIZE];
|
||||||
if !contains_pokemon(encrypted) {
|
if !contains_pokemon(encrypted) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let decrypted = decrypt_pokemon(encrypted).ok()?;
|
let decrypted = decrypt_pokemon(encrypted).ok()?;
|
||||||
// println!("{}", debug_pokemon_data(&decrypted));
|
println!("{}", debug_pokemon_data(&decrypted));
|
||||||
let pokemon = parse_pokemon(&decrypted).ok()?;
|
let pokemon = parse_pokemon(&decrypted).ok()?;
|
||||||
Some(pokemon)
|
Some(pokemon)
|
||||||
}
|
}
|
||||||
|
|
@ -113,40 +113,18 @@ fn decrypt_pokemon(encrypted: &[u8]) -> Result<Vec<u8>, String> {
|
||||||
Ok(unshuffled)
|
Ok(unshuffled)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pokemon(data: &[u8]) -> Result<PokemonInstance, String> {
|
fn parse_pokemon(data: &[u8]) -> Result<ParsedPokemonInstance, String> {
|
||||||
validate_size(data)?;
|
validate_size(data)?;
|
||||||
|
|
||||||
let mut instance = PokemonInstance::default();
|
let mut instance = ParsedPokemonInstance::default();
|
||||||
|
|
||||||
let offset_a: usize = 0x08 + 0 * BLOCK_SIZE;
|
let offset_a: usize = 0x08 + 0 * BLOCK_SIZE;
|
||||||
let offset_b: usize = 0x08 + 1 * BLOCK_SIZE;
|
let offset_b: usize = 0x08 + 1 * BLOCK_SIZE;
|
||||||
let offset_c: usize = 0x08 + 2 * BLOCK_SIZE;
|
let offset_c: usize = 0x08 + 2 * BLOCK_SIZE;
|
||||||
let offset_d: usize = 0x08 + 3 * BLOCK_SIZE;
|
let offset_d: usize = 0x08 + 3 * BLOCK_SIZE;
|
||||||
|
|
||||||
instance.pokemon.national = read_short(data, offset_a + 0x00);
|
instance.pokemon = read_short(data, offset_a + 0x00);
|
||||||
|
instance.ability = read_byte(data, offset_a + 0x0D);
|
||||||
let ivs = read_long(data, offset_b + 0x10);
|
|
||||||
instance.ivs.insert(BaseStat::Hp, ((ivs >> 0) & 31) as u8);
|
|
||||||
instance
|
|
||||||
.ivs
|
|
||||||
.insert(BaseStat::Attack, ((ivs >> 5) & 31) as u8);
|
|
||||||
instance
|
|
||||||
.ivs
|
|
||||||
.insert(BaseStat::Defense, ((ivs >> 10) & 31) as u8);
|
|
||||||
instance
|
|
||||||
.ivs
|
|
||||||
.insert(BaseStat::Speed, ((ivs >> 15) & 31) as u8);
|
|
||||||
instance
|
|
||||||
.ivs
|
|
||||||
.insert(BaseStat::SpecialAttack, ((ivs >> 20) & 31) as u8);
|
|
||||||
instance
|
|
||||||
.ivs
|
|
||||||
.insert(BaseStat::SpecialDefense, ((ivs >> 25) & 31) as u8);
|
|
||||||
|
|
||||||
instance.nature = Some(Nature {
|
|
||||||
pid: read_byte(data, offset_b + 0x19),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
|
|
||||||
instance
|
instance
|
||||||
.evs
|
.evs
|
||||||
|
|
@ -167,6 +145,26 @@ fn parse_pokemon(data: &[u8]) -> Result<PokemonInstance, String> {
|
||||||
.evs
|
.evs
|
||||||
.insert(BaseStat::SpecialDefense, read_byte(data, offset_a + 0x15));
|
.insert(BaseStat::SpecialDefense, read_byte(data, offset_a + 0x15));
|
||||||
|
|
||||||
|
let ivs = read_long(data, offset_b + 0x10);
|
||||||
|
instance.ivs.insert(BaseStat::Hp, ((ivs >> 0) & 31) as u8);
|
||||||
|
instance
|
||||||
|
.ivs
|
||||||
|
.insert(BaseStat::Attack, ((ivs >> 5) & 31) as u8);
|
||||||
|
instance
|
||||||
|
.ivs
|
||||||
|
.insert(BaseStat::Defense, ((ivs >> 10) & 31) as u8);
|
||||||
|
instance
|
||||||
|
.ivs
|
||||||
|
.insert(BaseStat::Speed, ((ivs >> 15) & 31) as u8);
|
||||||
|
instance
|
||||||
|
.ivs
|
||||||
|
.insert(BaseStat::SpecialAttack, ((ivs >> 20) & 31) as u8);
|
||||||
|
instance
|
||||||
|
.ivs
|
||||||
|
.insert(BaseStat::SpecialDefense, ((ivs >> 25) & 31) as u8);
|
||||||
|
|
||||||
|
instance.nature = read_byte(data, offset_b + 0x19);
|
||||||
|
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ use std::collections::HashMap;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_egui::EguiContexts;
|
use bevy_egui::EguiContexts;
|
||||||
|
|
||||||
use crate::{database::load_url_asset, pokemon::*};
|
use crate::{
|
||||||
|
database::{load_url_asset, Database},
|
||||||
|
pokemon::*,
|
||||||
|
};
|
||||||
|
|
||||||
use super::ui::{EguiAsset, UiAssets};
|
use super::ui::{EguiAsset, UiAssets};
|
||||||
|
|
||||||
|
|
@ -18,23 +21,82 @@ impl Plugin for InspectorPlugin {
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub struct Inspector {
|
pub struct Inspector {
|
||||||
pub battle: Battle,
|
pub battle: Battle<PokemonInstance>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct Battle {
|
pub struct Battle<T> {
|
||||||
pub player_party: Vec<PokemonInstance>,
|
pub player_party: Vec<T>,
|
||||||
pub enemy_party: Vec<PokemonInstance>,
|
pub enemy_party: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct PokemonInstance {
|
pub struct PokemonInstance {
|
||||||
pub pokemon: Pokemon,
|
pub pokemon: Pokemon,
|
||||||
|
pub ability: Option<Ability>,
|
||||||
pub nature: Option<Nature>,
|
pub nature: Option<Nature>,
|
||||||
pub ivs: HashMap<BaseStat, u8>,
|
pub ivs: HashMap<BaseStat, u8>,
|
||||||
pub evs: HashMap<BaseStat, u8>,
|
pub evs: HashMap<BaseStat, u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PokemonInstance {
|
||||||
|
pub fn from_parsed(
|
||||||
|
parsed: &ParsedPokemonInstance,
|
||||||
|
pokedex: &Res<Database<Pokemon>>,
|
||||||
|
natures: &Res<Database<Nature>>,
|
||||||
|
abilities: &Res<Database<Ability>>,
|
||||||
|
) -> Result<Self, String> {
|
||||||
|
let mut instance = PokemonInstance::default();
|
||||||
|
|
||||||
|
// pokemon data
|
||||||
|
if let Some(pokemon) = pokedex
|
||||||
|
.map
|
||||||
|
.values()
|
||||||
|
.find(|pokemon| pokemon.national == parsed.pokemon)
|
||||||
|
{
|
||||||
|
instance.pokemon = pokemon.clone();
|
||||||
|
} else {
|
||||||
|
return Err(format!("National dex not found: {}", parsed.pokemon));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ability data
|
||||||
|
if let Some(ability) = abilities
|
||||||
|
.map
|
||||||
|
.values()
|
||||||
|
.find(|ability| ability.id == parsed.ability as u16)
|
||||||
|
{
|
||||||
|
instance.ability = Some(ability.clone());
|
||||||
|
} else {
|
||||||
|
return Err(format!("Ability id not found: {}", parsed.ability));
|
||||||
|
}
|
||||||
|
|
||||||
|
// nature data
|
||||||
|
if let Some(nature) = natures
|
||||||
|
.map
|
||||||
|
.values()
|
||||||
|
.find(|nature| nature.pid == parsed.nature)
|
||||||
|
{
|
||||||
|
instance.nature = Some(nature.clone());
|
||||||
|
} else {
|
||||||
|
return Err(format!("Nature pid not found: {}", parsed.nature));
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.ivs = parsed.ivs.clone();
|
||||||
|
instance.evs = parsed.evs.clone();
|
||||||
|
|
||||||
|
Ok(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct ParsedPokemonInstance {
|
||||||
|
pub pokemon: u16,
|
||||||
|
pub ability: u8,
|
||||||
|
pub nature: u8,
|
||||||
|
pub ivs: HashMap<BaseStat, u8>,
|
||||||
|
pub evs: HashMap<BaseStat, u8>,
|
||||||
|
}
|
||||||
|
|
||||||
fn state_changed(
|
fn state_changed(
|
||||||
inspector: Res<Inspector>,
|
inspector: Res<Inspector>,
|
||||||
assets: Res<AssetServer>,
|
assets: Res<AssetServer>,
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,13 @@ use std::{
|
||||||
|
|
||||||
use crate::{database::Database, pokemon::*};
|
use crate::{database::Database, pokemon::*};
|
||||||
|
|
||||||
use super::{
|
use super::{battle::parse_battle_party, inspector::*};
|
||||||
battle::parse_battle_party,
|
|
||||||
inspector::{Battle, Inspector},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct MemoryReaderPlugin;
|
pub struct MemoryReaderPlugin;
|
||||||
|
|
||||||
impl Plugin for MemoryReaderPlugin {
|
impl Plugin for MemoryReaderPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<ParsedBattleEvent>()
|
app.add_event::<BattleEvent>()
|
||||||
.insert_resource(EventQueue::default())
|
.insert_resource(EventQueue::default())
|
||||||
.add_startup_system(init_memory_reader)
|
.add_startup_system(init_memory_reader)
|
||||||
.add_system(flush_updates)
|
.add_system(flush_updates)
|
||||||
|
|
@ -27,54 +24,40 @@ impl Plugin for MemoryReaderPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ParsedBattleEvent(Battle);
|
pub struct BattleEvent(Battle<PokemonInstance>);
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
struct EventQueue {
|
struct EventQueue {
|
||||||
updates: Arc<Mutex<Vec<ParsedBattleEvent>>>,
|
updates: Arc<Mutex<Vec<Battle<ParsedPokemonInstance>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_updates(
|
fn flush_updates(
|
||||||
queue: Res<EventQueue>,
|
queue: Res<EventQueue>,
|
||||||
pokedex: Res<Database<Pokemon>>,
|
pokedex: Res<Database<Pokemon>>,
|
||||||
|
abilities: Res<Database<Ability>>,
|
||||||
natures: Res<Database<Nature>>,
|
natures: Res<Database<Nature>>,
|
||||||
mut events: EventWriter<ParsedBattleEvent>,
|
mut events: EventWriter<BattleEvent>,
|
||||||
) {
|
) {
|
||||||
match queue.updates.lock() {
|
match queue.updates.lock() {
|
||||||
Ok(mut updates) => {
|
Ok(mut updates) => {
|
||||||
for mut update in updates.drain(..) {
|
for update in updates.drain(..) {
|
||||||
for mut instance in update
|
let mut battle = Battle::default();
|
||||||
.0
|
|
||||||
.player_party
|
|
||||||
.iter_mut()
|
|
||||||
.chain(update.0.enemy_party.iter_mut())
|
|
||||||
{
|
|
||||||
// Fill pokemon data
|
|
||||||
if let Some(pokemon) = pokedex
|
|
||||||
.map
|
|
||||||
.values()
|
|
||||||
.find(|pokemon| pokemon.national == instance.pokemon.national)
|
|
||||||
{
|
|
||||||
instance.pokemon = pokemon.clone();
|
|
||||||
} else {
|
|
||||||
warn!("National dex not found: {}", instance.pokemon.national);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill nature data
|
for parsed in update.player_party.iter() {
|
||||||
if let Some(instance_nature) = instance.nature.clone() {
|
match PokemonInstance::from_parsed(parsed, &pokedex, &natures, &abilities) {
|
||||||
if let Some(nature) = natures
|
Ok(instance) => battle.player_party.push(instance),
|
||||||
.map
|
Err(err) => warn!("{err}"),
|
||||||
.values()
|
|
||||||
.find(|nature| nature.pid == instance_nature.pid)
|
|
||||||
{
|
|
||||||
instance.nature = Some(nature.clone());
|
|
||||||
} else {
|
|
||||||
warn!("Nature pid not found: {}", instance_nature.pid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
events.send(update)
|
for parsed in update.enemy_party.iter() {
|
||||||
|
match PokemonInstance::from_parsed(parsed, &pokedex, &natures, &abilities) {
|
||||||
|
Ok(instance) => battle.enemy_party.push(instance),
|
||||||
|
Err(err) => warn!("{err}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
events.send(BattleEvent(battle))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -83,7 +66,7 @@ fn flush_updates(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_inspector(mut inspector: ResMut<Inspector>, mut events: EventReader<ParsedBattleEvent>) {
|
fn update_inspector(mut inspector: ResMut<Inspector>, mut events: EventReader<BattleEvent>) {
|
||||||
for event in events.iter() {
|
for event in events.iter() {
|
||||||
inspector.battle = event.0.clone();
|
inspector.battle = event.0.clone();
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +96,7 @@ fn init_memory_reader(queue: Res<EventQueue>) {
|
||||||
match fs::read(&event.path) {
|
match fs::read(&event.path) {
|
||||||
Ok(data) => match parse_battle_party(&data) {
|
Ok(data) => match parse_battle_party(&data) {
|
||||||
Ok(battle) => match updates.lock() {
|
Ok(battle) => match updates.lock() {
|
||||||
Ok(mut updates) => updates.push(ParsedBattleEvent(battle)),
|
Ok(mut updates) => updates.push(battle),
|
||||||
Err(err) => error!("{err}"),
|
Err(err) => error!("{err}"),
|
||||||
},
|
},
|
||||||
Err(err) => error!("Failed to parse party data: ${err}"),
|
Err(err) => error!("Failed to parse party data: ${err}"),
|
||||||
|
|
|
||||||
103
src/ivpeek/ui.rs
103
src/ivpeek/ui.rs
|
|
@ -9,7 +9,7 @@ use super::inspector::{Inspector, PokemonInstance};
|
||||||
|
|
||||||
const BAR_HEIGHT: f32 = 12.0;
|
const BAR_HEIGHT: f32 = 12.0;
|
||||||
const SPRITE_SIZE: f32 = 128.0;
|
const SPRITE_SIZE: f32 = 128.0;
|
||||||
const SPRITE_PADDING: f32 = 32.0;
|
const SPRITE_PADDING: f32 = 16.0;
|
||||||
const BASE_STAT_WIDTH_MULT: f32 = 0.5;
|
const BASE_STAT_WIDTH_MULT: f32 = 0.5;
|
||||||
const IV_WIDTH_MULT: f32 = 4.0;
|
const IV_WIDTH_MULT: f32 = 4.0;
|
||||||
const EV_WIDTH_MULT: f32 = 0.25;
|
const EV_WIDTH_MULT: f32 = 0.25;
|
||||||
|
|
@ -106,66 +106,69 @@ fn render_pokemon_instance(
|
||||||
) {
|
) {
|
||||||
let sprite_size = egui::Vec2::new(SPRITE_SIZE, SPRITE_SIZE);
|
let sprite_size = egui::Vec2::new(SPRITE_SIZE, SPRITE_SIZE);
|
||||||
let pokemon = instance.pokemon.clone();
|
let pokemon = instance.pokemon.clone();
|
||||||
|
let ability = instance.ability.clone();
|
||||||
let nature = instance.nature.clone();
|
let nature = instance.nature.clone();
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.set_min_width(sprite_size.x + SPRITE_PADDING);
|
ui.horizontal(|ui| {
|
||||||
ui.set_max_width(sprite_size.x + SPRITE_PADDING);
|
ui.set_min_width(sprite_size.x + SPRITE_PADDING);
|
||||||
// Name
|
ui.set_max_width(sprite_size.x + SPRITE_PADDING);
|
||||||
ui.label(egui::RichText::new(&pokemon.full_name).color(egui::Color32::LIGHT_GRAY));
|
// Name
|
||||||
|
ui.label(egui::RichText::new(&pokemon.full_name).color(egui::Color32::LIGHT_GRAY));
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
ui.label(format!(
|
ui.label(format!(
|
||||||
"{} / {}",
|
"{} / {}",
|
||||||
pokemon.type1.as_ref().map_or("-", |t| t.name.as_str()),
|
pokemon.type1.as_ref().map_or("-", |t| t.name.as_str()),
|
||||||
pokemon.type2.as_ref().map_or("-", |t| t.name.as_str())
|
pokemon.type2.as_ref().map_or("-", |t| t.name.as_str())
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Headings
|
ui.label(ability.as_ref().map_or("-", |a| a.name.as_str()));
|
||||||
ui.horizontal(|ui| {
|
|
||||||
for (i, width) in COLUMNS.iter().enumerate() {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.set_width(*width);
|
|
||||||
match i {
|
|
||||||
1 => {
|
|
||||||
ui.label(egui::RichText::new("Base stat"));
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
ui.label(egui::RichText::new("EV"));
|
|
||||||
}
|
|
||||||
3 => {
|
|
||||||
ui.label(egui::RichText::new(format!(
|
|
||||||
"{} / 510",
|
|
||||||
instance.evs.values().map(|v| *v as i32).sum::<i32>()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
5 => {
|
|
||||||
ui.label(egui::RichText::new("IV"));
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
// Sprite
|
||||||
// Sprite
|
ui.horizontal(|ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.set_min_size(sprite_size);
|
||||||
ui.set_min_size(sprite_size);
|
ui.set_max_size(sprite_size);
|
||||||
ui.set_max_size(sprite_size);
|
if let Some(EguiAsset(_, rendered_texture_id)) =
|
||||||
if let Some(EguiAsset(_, rendered_texture_id)) =
|
ui_assets.sprite_map.get(&pokemon.key())
|
||||||
ui_assets.sprite_map.get(&pokemon.key())
|
{
|
||||||
{
|
ui.add(egui::Image::new(*rendered_texture_id, sprite_size));
|
||||||
ui.add(egui::Image::new(*rendered_texture_id, sprite_size));
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.add_space(SPRITE_PADDING);
|
ui.add_space(SPRITE_PADDING);
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
|
ui.add_space(16.);
|
||||||
|
// Headings
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
for (i, width) in COLUMNS.iter().enumerate() {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.set_width(*width);
|
||||||
|
match i {
|
||||||
|
1 => {
|
||||||
|
ui.label(egui::RichText::new("Base stat"));
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
ui.label(egui::RichText::new("EV"));
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
ui.label(egui::RichText::new(format!(
|
||||||
|
"{} / 510",
|
||||||
|
instance.evs.values().map(|v| *v as i32).sum::<i32>()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
ui.label(egui::RichText::new("IV"));
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
for stat in BaseStat::all() {
|
for stat in BaseStat::all() {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let mut column_size = COLUMNS.iter();
|
let mut column_size = COLUMNS.iter();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,10 @@ pub fn parse_json_file<P: AsRef<Path>>(path: P) -> JsonValue {
|
||||||
json::parse(fs::read_to_string(path).unwrap().as_ref()).unwrap()
|
json::parse(fs::read_to_string(path).unwrap().as_ref()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_abilities() -> JsonValue {
|
||||||
|
parse_json_file(DATA_DIR.join("abilities.json"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_natures() -> JsonValue {
|
pub fn read_natures() -> JsonValue {
|
||||||
parse_json_file(DATA_DIR.join("natures.json"))
|
parse_json_file(DATA_DIR.join("natures.json"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,30 @@ impl GetKey for Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone)]
|
||||||
|
pub struct Ability {
|
||||||
|
pub id: u16,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromJson for Ability {
|
||||||
|
fn from_json(json: &json::JsonValue) -> Option<Self>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Some(Self {
|
||||||
|
id: json["id"].as_u16()?,
|
||||||
|
name: json["name"].as_str()?.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetKey for Ability {
|
||||||
|
fn key(&self) -> String {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Reflect, FromReflect, PartialEq)]
|
#[derive(Default, Debug, Clone, Reflect, FromReflect, PartialEq)]
|
||||||
pub struct Nature {
|
pub struct Nature {
|
||||||
pub id: u8,
|
pub id: u8,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue