initial commit
commit
d90540daa7
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "smart-iv-calculator"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bevy = "0.10.0"
|
||||
bevy_egui = "0.20.1"
|
||||
json = "0.12.4"
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
# Enable a small amount of optimization in debug mode
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
||||
# Enable high optimizations for dependencies (incl. Bevy), but not for our code:
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 3
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Dependencies
|
||||
|
||||
- rust / cargo
|
||||
|
||||
Linux users might require some `XCB` libraries to use `bevy_egui`. These packages that can be installed on Debian-based systems with the following command:
|
||||
|
||||
```bash
|
||||
sudo apt install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 94 B |
|
|
@ -0,0 +1,211 @@
|
|||
[{
|
||||
"stat": "hp",
|
||||
"name": "Loves to eat",
|
||||
"possible_values": [
|
||||
0, 5, 10, 15, 20, 25, 30
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "hp",
|
||||
"name": "Often dozes off",
|
||||
"possible_values": [
|
||||
1, 6, 11, 16, 21, 26, 31
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "hp",
|
||||
"name": "Often scatters things",
|
||||
"possible_values": [
|
||||
2, 7, 12, 17, 22, 27
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "hp",
|
||||
"name": "Scatters things often",
|
||||
"possible_values": [
|
||||
3, 8, 13, 18, 23, 28
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "hp",
|
||||
"name": "Likes to Relax",
|
||||
"possible_values": [
|
||||
4, 9, 14, 19, 24, 29
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "attack",
|
||||
"name": "Proud of its power",
|
||||
"possible_values": [
|
||||
0, 5, 10, 15, 20, 25, 30
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "attack",
|
||||
"name": "Likes to thrash about",
|
||||
"possible_values": [
|
||||
1, 6, 11, 16, 21, 26, 31
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "attack",
|
||||
"name": "A little quick tempered",
|
||||
"possible_values": [
|
||||
2, 7, 12, 17, 22, 27
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "attack",
|
||||
"name": "Likes to fight",
|
||||
"possible_values": [
|
||||
3, 8, 13, 18, 23, 28
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "attack",
|
||||
"name": "Quick Tempered",
|
||||
"possible_values": [
|
||||
4, 9, 14, 19, 24, 29
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "defense",
|
||||
"name": "Sturdy body",
|
||||
"possible_values": [
|
||||
0, 5, 10, 15, 20, 25, 30
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "defense",
|
||||
"name": "Capable of taking hits",
|
||||
"possible_values": [
|
||||
1, 6, 11, 16, 21, 26, 31
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "defense",
|
||||
"name": "Highly persistent",
|
||||
"possible_values": [
|
||||
2, 7, 12, 17, 22, 27
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "defense",
|
||||
"name": "Good endurance",
|
||||
"possible_values": [
|
||||
3, 8, 13, 18, 23, 28
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "defense",
|
||||
"name": "Good perseverance",
|
||||
"possible_values": [
|
||||
4, 9, 14, 19, 24, 29
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_attack",
|
||||
"name": "Highly curious",
|
||||
"possible_values": [
|
||||
0, 5, 10, 15, 20, 25, 30
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_attack",
|
||||
"name": "Mischievous",
|
||||
"possible_values": [
|
||||
1, 6, 11, 16, 21, 26, 31
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_attack",
|
||||
"name": "Thoroughly Cunning",
|
||||
"possible_values": [
|
||||
2, 7, 12, 17, 22, 27
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_attack",
|
||||
"name": "Often lost in thought",
|
||||
"possible_values": [
|
||||
3, 8, 13, 18, 23, 28
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_attack",
|
||||
"name": "Very finicky",
|
||||
"possible_values": [
|
||||
4, 9, 14, 19, 24, 29
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_defense",
|
||||
"name": "Strong willed",
|
||||
"possible_values": [
|
||||
0, 5, 10, 15, 20, 25, 30
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_defense",
|
||||
"name": "Somewhat vain",
|
||||
"possible_values": [
|
||||
1, 6, 11, 16, 21, 26, 31
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_defense",
|
||||
"name": "Strongly defiant",
|
||||
"possible_values": [
|
||||
2, 7, 12, 17, 22, 27
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_defense",
|
||||
"name": "Hates to lose",
|
||||
"possible_values": [
|
||||
3, 8, 13, 18, 23, 28
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "special_defense",
|
||||
"name": "Somewhat stubborn",
|
||||
"possible_values": [
|
||||
4, 9, 14, 19, 24, 29
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "speed",
|
||||
"name": "Likes to run",
|
||||
"possible_values": [
|
||||
0, 5, 10, 15, 20, 25, 30
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "speed",
|
||||
"name": "Alert to sounds",
|
||||
"possible_values": [
|
||||
1, 6, 11, 16, 21, 26, 31
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "speed",
|
||||
"name": "Impetuous and silly",
|
||||
"possible_values": [
|
||||
2, 7, 12, 17, 22, 27
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "speed",
|
||||
"name": "Somewhat of a clown",
|
||||
"possible_values": [
|
||||
3, 8, 13, 18, 23, 28
|
||||
]
|
||||
},
|
||||
{
|
||||
"stat": "speed",
|
||||
"name": "Quick to flee",
|
||||
"possible_values": [
|
||||
4, 9, 14, 19, 24, 29
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
[{
|
||||
"name": "Hardy",
|
||||
"alias": "hardy",
|
||||
"id": 1,
|
||||
"increased": null,
|
||||
"decreased": null
|
||||
},
|
||||
{
|
||||
"name": "Bold",
|
||||
"alias": "bold",
|
||||
"id": 2,
|
||||
"increased": "defense",
|
||||
"decreased": "attack"
|
||||
},
|
||||
{
|
||||
"name": "Modest",
|
||||
"alias": "modest",
|
||||
"id": 3,
|
||||
"increased": "special_attack",
|
||||
"decreased": "attack"
|
||||
},
|
||||
{
|
||||
"name": "Calm",
|
||||
"alias": "calm",
|
||||
"id": 4,
|
||||
"increased": "special_defense",
|
||||
"decreased": "attack"
|
||||
},
|
||||
{
|
||||
"name": "Timid",
|
||||
"alias": "timid",
|
||||
"id": 5,
|
||||
"increased": "speed",
|
||||
"decreased": "attack"
|
||||
},
|
||||
{
|
||||
"name": "Lonely",
|
||||
"alias": "lonely",
|
||||
"id": 6,
|
||||
"increased": "attack",
|
||||
"decreased": "defense"
|
||||
},
|
||||
{
|
||||
"name": "Docile",
|
||||
"alias": "docile",
|
||||
"id": 7,
|
||||
"increased": null,
|
||||
"decreased": null
|
||||
},
|
||||
{
|
||||
"name": "Mild",
|
||||
"alias": "mild",
|
||||
"id": 8,
|
||||
"increased": "special_attack",
|
||||
"decreased": "defense"
|
||||
},
|
||||
{
|
||||
"name": "Gentle",
|
||||
"alias": "gentle",
|
||||
"id": 9,
|
||||
"increased": "special_defense",
|
||||
"decreased": "defense"
|
||||
},
|
||||
{
|
||||
"name": "Hasty",
|
||||
"alias": "hasty",
|
||||
"id": 10,
|
||||
"increased": "speed",
|
||||
"decreased": "defense"
|
||||
},
|
||||
{
|
||||
"name": "Adamant",
|
||||
"alias": "adamant",
|
||||
"id": 11,
|
||||
"increased": "attack",
|
||||
"decreased": "special_attack"
|
||||
},
|
||||
{
|
||||
"name": "Impish",
|
||||
"alias": "impish",
|
||||
"id": 12,
|
||||
"increased": "defense",
|
||||
"decreased": "special_attack"
|
||||
},
|
||||
{
|
||||
"name": "Bashful",
|
||||
"alias": "bashful",
|
||||
"id": 13,
|
||||
"increased": null,
|
||||
"decreased": null
|
||||
},
|
||||
{
|
||||
"name": "Careful",
|
||||
"alias": "careful",
|
||||
"id": 14,
|
||||
"increased": "special_defense",
|
||||
"decreased": "special_attack"
|
||||
},
|
||||
{
|
||||
"name": "Rash",
|
||||
"alias": "rash",
|
||||
"id": 15,
|
||||
"increased": "special_attack",
|
||||
"decreased": "special_defense"
|
||||
},
|
||||
{
|
||||
"name": "Jolly",
|
||||
"alias": "jolly",
|
||||
"id": 16,
|
||||
"increased": "speed",
|
||||
"decreased": "special_attack"
|
||||
},
|
||||
{
|
||||
"name": "Naughty",
|
||||
"alias": "naughty",
|
||||
"id": 17,
|
||||
"increased": "attack",
|
||||
"decreased": "special_defense"
|
||||
},
|
||||
{
|
||||
"name": "Lax",
|
||||
"alias": "lax",
|
||||
"id": 18,
|
||||
"increased": "defense",
|
||||
"decreased": "special_defense"
|
||||
},
|
||||
{
|
||||
"name": "Quirky",
|
||||
"alias": "quirky",
|
||||
"id": 19,
|
||||
"increased": null,
|
||||
"decreased": null
|
||||
},
|
||||
{
|
||||
"name": "Naive",
|
||||
"alias": "naive",
|
||||
"id": 20,
|
||||
"increased": "speed",
|
||||
"decreased": "special_defense"
|
||||
},
|
||||
{
|
||||
"name": "Brave",
|
||||
"alias": "brave",
|
||||
"id": 21,
|
||||
"increased": "attack",
|
||||
"decreased": "speed"
|
||||
},
|
||||
{
|
||||
"name": "Relaxed",
|
||||
"alias": "relaxed",
|
||||
"id": 22,
|
||||
"increased": "defense",
|
||||
"decreased": "speed"
|
||||
},
|
||||
{
|
||||
"name": "Quiet",
|
||||
"alias": "quiet",
|
||||
"id": 23,
|
||||
"increased": "special_attack",
|
||||
"decreased": "speed"
|
||||
},
|
||||
{
|
||||
"name": "Sassy",
|
||||
"alias": "sassy",
|
||||
"id": 24,
|
||||
"increased": "special_defense",
|
||||
"decreased": "speed"
|
||||
},
|
||||
{
|
||||
"name": "Serious",
|
||||
"alias": "serious",
|
||||
"id": 25,
|
||||
"increased": null,
|
||||
"decreased": null
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,91 @@
|
|||
[{
|
||||
"id": 1,
|
||||
"name": "Normal",
|
||||
"alias": "normal"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Fire",
|
||||
"alias": "fire"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Water",
|
||||
"alias": "water"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Electric",
|
||||
"alias": "electric"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Grass",
|
||||
"alias": "grass"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Ice",
|
||||
"alias": "ice"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Fighting",
|
||||
"alias": "fighting"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "Poison",
|
||||
"alias": "poison"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Ground",
|
||||
"alias": "ground"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Flying",
|
||||
"alias": "flying"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "Psychic",
|
||||
"alias": "psychic"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "Bug",
|
||||
"alias": "bug"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "Rock",
|
||||
"alias": "rock"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"name": "Ghost",
|
||||
"alias": "ghost"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"name": "Dragon",
|
||||
"alias": "dragon"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"name": "Dark",
|
||||
"alias": "dark"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"name": "Steel",
|
||||
"alias": "steel"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"name": "Fairy",
|
||||
"alias": "fairy"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
use bevy::prelude::*;
|
||||
use json::JsonValue;
|
||||
use lazy_static::lazy_static;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use crate::pokemon::*;
|
||||
|
||||
lazy_static! {
|
||||
static ref DATA_DIR: PathBuf = "./data".into();
|
||||
pub static ref TYPE_MAP: HashMap<u8, Type> = {
|
||||
let types = parse_json_file(DATA_DIR.join("types.json"));
|
||||
let mut map = HashMap::new();
|
||||
for type_data in types.members() {
|
||||
if let Some(type_data) = Type::from_json(type_data) {
|
||||
map.insert(type_data.id, type_data);
|
||||
}
|
||||
}
|
||||
map
|
||||
};
|
||||
}
|
||||
|
||||
pub struct DatabasePlugin;
|
||||
|
||||
impl Plugin for DatabasePlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.insert_resource(Database::<Pokemon>::default())
|
||||
.insert_resource(Database::<Nature>::default())
|
||||
.insert_resource(Database::<Characteristic>::default())
|
||||
.add_startup_system(database_setup);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct Database<T> {
|
||||
pub map: HashMap<String, T>,
|
||||
}
|
||||
|
||||
impl<T> Database<T>
|
||||
where
|
||||
T: FromJson + GetKey,
|
||||
{
|
||||
fn populate_from_json(&mut self, json: &JsonValue) {
|
||||
for item in json.members() {
|
||||
if let Some(item) = T::from_json(item) {
|
||||
let key = item.alias();
|
||||
if !self.map.contains_key(&key) {
|
||||
self.map.insert(key, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn database_setup(
|
||||
mut pokemon_database: ResMut<Database<Pokemon>>,
|
||||
mut nature_database: ResMut<Database<Nature>>,
|
||||
mut characteristic_database: ResMut<Database<Characteristic>>,
|
||||
) {
|
||||
let natures = parse_json_file(DATA_DIR.join("natures.json"));
|
||||
nature_database.populate_from_json(&natures);
|
||||
let pokedex = parse_json_file(DATA_DIR.join("pokedex.json"));
|
||||
pokemon_database.populate_from_json(&pokedex);
|
||||
let characteristics = parse_json_file(DATA_DIR.join("characteristics.json"));
|
||||
characteristic_database.populate_from_json(&characteristics);
|
||||
}
|
||||
|
||||
pub fn parse_json_file<P: AsRef<Path>>(path: P) -> JsonValue {
|
||||
json::parse(fs::read_to_string(path).unwrap().as_ref()).unwrap()
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
use crate::{database::Database, pokemon::*};
|
||||
|
||||
pub struct InspectorPlugin;
|
||||
|
||||
impl Plugin for InspectorPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.register_type::<InspectorPokemon>()
|
||||
.insert_resource(InspectorPokemon::default())
|
||||
.add_startup_system(resource_setup);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Reflect, Resource, Default, Debug, Clone)]
|
||||
#[reflect(Resource)]
|
||||
pub struct InspectorPokemon {
|
||||
pub pokemon: Option<Pokemon>,
|
||||
pub nature: Option<Nature>,
|
||||
pub characteristic: Option<Characteristic>,
|
||||
}
|
||||
|
||||
fn resource_setup(
|
||||
mut inspector: ResMut<InspectorPokemon>,
|
||||
pokemon: Res<Database<Pokemon>>,
|
||||
natures: Res<Database<Nature>>,
|
||||
) {
|
||||
inspector.pokemon = pokemon.map.get("sceptile").cloned();
|
||||
inspector.nature = natures.map.get("adamant").cloned();
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
use bevy::{prelude::*, window::WindowResolution};
|
||||
|
||||
pub mod database;
|
||||
pub mod inspector;
|
||||
pub mod pokemon;
|
||||
pub mod ui;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(
|
||||
DefaultPlugins
|
||||
.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
resolution: WindowResolution::new(720., 540.),
|
||||
resizable: false,
|
||||
title: "Smart IV calculator".to_string(),
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
})
|
||||
.set(ImagePlugin::default_nearest()),
|
||||
)
|
||||
.add_plugin(database::DatabasePlugin)
|
||||
.add_plugin(inspector::InspectorPlugin)
|
||||
.add_plugin(ui::UiPlugin)
|
||||
.run();
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
use bevy::reflect::{FromReflect, Reflect};
|
||||
use lazy_static::lazy_static;
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
use crate::database::TYPE_MAP;
|
||||
|
||||
pub type BaseValue = u8;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BASESTAT_MAP: HashMap<String, BaseStat> = {
|
||||
let mut map = HashMap::new();
|
||||
map.insert(String::from("hp"), BaseStat::Hp);
|
||||
map.insert(String::from("attack"), BaseStat::Attack);
|
||||
map.insert(String::from("defense"), BaseStat::Defense);
|
||||
map.insert(String::from("special_attack"), BaseStat::SpecialAttack);
|
||||
map.insert(String::from("special_defense"), BaseStat::SpecialDefense);
|
||||
map.insert(String::from("speed"), BaseStat::Speed);
|
||||
map
|
||||
};
|
||||
}
|
||||
|
||||
pub trait FromJson {
|
||||
fn from_json(json: &json::JsonValue) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
pub trait GetKey {
|
||||
fn alias(&self) -> String;
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct DerivedStats {
|
||||
pub level: Option<i32>,
|
||||
pub stats: HashMap<BaseStat, i32>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Reflect, FromReflect)]
|
||||
pub struct Pokemon {
|
||||
pub id: u16,
|
||||
pub national: u16,
|
||||
pub name: String,
|
||||
pub alias: String,
|
||||
pub full_name: String,
|
||||
pub image: String,
|
||||
pub form: String,
|
||||
pub form_alias: String,
|
||||
pub gen_id: u8,
|
||||
pub type1: Option<Type>,
|
||||
pub type2: Option<Type>,
|
||||
pub hp: BaseValue,
|
||||
pub attack: BaseValue,
|
||||
pub defense: BaseValue,
|
||||
pub special_attack: BaseValue,
|
||||
pub special_defense: BaseValue,
|
||||
pub speed: BaseValue,
|
||||
}
|
||||
|
||||
impl Pokemon {
|
||||
pub fn base_value(&self, stat: BaseStat) -> BaseValue {
|
||||
match stat {
|
||||
BaseStat::Hp => self.hp,
|
||||
BaseStat::Attack => self.attack,
|
||||
BaseStat::Defense => self.defense,
|
||||
BaseStat::SpecialAttack => self.special_attack,
|
||||
BaseStat::SpecialDefense => self.special_defense,
|
||||
BaseStat::Speed => self.speed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromJson for Pokemon {
|
||||
fn from_json(json: &json::JsonValue) -> Option<Self> {
|
||||
Some(Self {
|
||||
id: json["id"].as_u16()?,
|
||||
national: json["national"].as_u16()?,
|
||||
name: json["name"].as_str()?.to_string(),
|
||||
alias: json["alias"].as_str()?.to_string(),
|
||||
full_name: json["full_name"].as_str()?.to_string(),
|
||||
image: json["image"].as_str()?.to_string(),
|
||||
form: json["form"].as_str()?.to_string(),
|
||||
form_alias: json["form_alias"].as_str()?.to_string(),
|
||||
gen_id: json["gen_id"].as_u8()?,
|
||||
type1: json["type1"]
|
||||
.as_u8()
|
||||
.map_or(None, |value| TYPE_MAP.get(&value).cloned()),
|
||||
type2: json["type2"]
|
||||
.as_u8()
|
||||
.map_or(None, |value| TYPE_MAP.get(&value).cloned()),
|
||||
hp: json["hp"].as_u8()?,
|
||||
attack: json["attack"].as_u8()?,
|
||||
defense: json["defense"].as_u8()?,
|
||||
special_attack: json["special_attack"].as_u8()?,
|
||||
special_defense: json["special_defense"].as_u8()?,
|
||||
speed: json["speed"].as_u8()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetKey for Pokemon {
|
||||
fn alias(&self) -> String {
|
||||
self.alias.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Reflect, FromReflect, Default, PartialEq)]
|
||||
pub enum BaseStat {
|
||||
#[default]
|
||||
Hp,
|
||||
Attack,
|
||||
Defense,
|
||||
SpecialAttack,
|
||||
SpecialDefense,
|
||||
Speed,
|
||||
}
|
||||
|
||||
impl fmt::Display for BaseStat {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let name = match self {
|
||||
BaseStat::Hp => "HP",
|
||||
BaseStat::Attack => "Attack",
|
||||
BaseStat::Defense => "Defense",
|
||||
BaseStat::SpecialAttack => "Sp.Atk",
|
||||
BaseStat::SpecialDefense => "Sp.Def",
|
||||
BaseStat::Speed => "Speed",
|
||||
};
|
||||
write!(f, "{}", name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Reflect, FromReflect)]
|
||||
pub struct Type {
|
||||
pub id: u8,
|
||||
pub name: String,
|
||||
pub alias: String,
|
||||
}
|
||||
|
||||
impl FromJson for Type {
|
||||
fn from_json(json: &json::JsonValue) -> Option<Self> {
|
||||
Some(Self {
|
||||
id: json["id"].as_u8()?,
|
||||
name: json["name"].as_str()?.to_string(),
|
||||
alias: json["alias"].as_str()?.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetKey for Type {
|
||||
fn alias(&self) -> String {
|
||||
self.alias.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Reflect, FromReflect)]
|
||||
pub struct Nature {
|
||||
pub id: u8,
|
||||
pub name: String,
|
||||
pub alias: String,
|
||||
pub increased: Option<BaseStat>,
|
||||
pub decreased: Option<BaseStat>,
|
||||
}
|
||||
|
||||
impl FromJson for Nature {
|
||||
fn from_json(json: &json::JsonValue) -> Option<Self> {
|
||||
Some(Self {
|
||||
id: json["id"].as_u8()?,
|
||||
name: json["name"].as_str()?.to_string(),
|
||||
alias: json["alias"].as_str()?.to_string(),
|
||||
increased: json["increased"]
|
||||
.as_str()
|
||||
.map_or(None, |value| BASESTAT_MAP.get(value).copied()),
|
||||
decreased: json["decreased"]
|
||||
.as_str()
|
||||
.map_or(None, |value| BASESTAT_MAP.get(value).copied()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetKey for Nature {
|
||||
fn alias(&self) -> String {
|
||||
self.alias.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Reflect, FromReflect)]
|
||||
pub struct Characteristic {
|
||||
stat: BaseStat,
|
||||
name: String,
|
||||
possible_values: Vec<u8>,
|
||||
}
|
||||
|
||||
impl FromJson for Characteristic {
|
||||
fn from_json(json: &json::JsonValue) -> Option<Self> {
|
||||
Some(Self {
|
||||
stat: json["stat"].as_str().map_or(BaseStat::default(), |value| {
|
||||
BASESTAT_MAP.get(value).cloned().unwrap_or_default()
|
||||
}),
|
||||
name: json["name"].as_str()?.to_string(),
|
||||
possible_values: json["possible_values"]
|
||||
.members()
|
||||
.map_while(|value| value.as_u8())
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetKey for Characteristic {
|
||||
fn alias(&self) -> String {
|
||||
self.name.to_lowercase()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_egui::{egui, EguiContexts, EguiPlugin};
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use crate::{database::Database, inspector::InspectorPokemon, pokemon::*};
|
||||
|
||||
lazy_static! {
|
||||
static ref BASE_STAT_COLOR_RANGES: Vec<(u8, egui::Color32)> = vec![
|
||||
(0, egui::Color32::from_rgb(255, 0, 0)),
|
||||
(30, egui::Color32::from_rgb(255, 128, 0)),
|
||||
(60, egui::Color32::from_rgb(255, 255, 0)),
|
||||
(90, egui::Color32::from_rgb(128, 255, 0)),
|
||||
(120, egui::Color32::from_rgb(0, 255, 0)),
|
||||
(150, egui::Color32::from_rgb(0, 255, 128)),
|
||||
(180, egui::Color32::from_rgb(0, 255, 255)),
|
||||
];
|
||||
}
|
||||
|
||||
pub struct UiPlugin;
|
||||
|
||||
impl Plugin for UiPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_plugin(EguiPlugin)
|
||||
.insert_resource(UiAssets::default())
|
||||
.insert_resource(UiState::default())
|
||||
.add_startup_system(load_assets)
|
||||
.add_system(handle_state)
|
||||
.add_system(ui_system);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource, Default, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct UiAssets {
|
||||
bar_handle: Handle<Image>,
|
||||
}
|
||||
|
||||
#[derive(Resource, Default, Reflect)]
|
||||
#[reflect(Resource)]
|
||||
pub struct UiState {
|
||||
name: String,
|
||||
nature: String,
|
||||
}
|
||||
|
||||
fn load_assets(mut ui_assets: ResMut<UiAssets>, assets: Res<AssetServer>) {
|
||||
ui_assets.bar_handle = assets.load("ui/bar.png");
|
||||
}
|
||||
|
||||
fn handle_state(
|
||||
ui_state: Res<UiState>,
|
||||
pokemon: Res<Database<Pokemon>>,
|
||||
nature: Res<Database<Nature>>,
|
||||
mut inspector: ResMut<InspectorPokemon>,
|
||||
) {
|
||||
if ui_state.is_changed() {
|
||||
if let Some(pokemon) = pokemon.map.get(ui_state.name.to_lowercase().as_str()) {
|
||||
inspector.pokemon = Some(pokemon.clone());
|
||||
}
|
||||
|
||||
if let Some(nature) = nature.map.get(ui_state.nature.to_lowercase().as_str()) {
|
||||
inspector.nature = Some(nature.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ui_system(
|
||||
mut contexts: EguiContexts,
|
||||
inspector: Res<InspectorPokemon>,
|
||||
ui_assets: Res<UiAssets>,
|
||||
mut ui_state: ResMut<UiState>,
|
||||
mut rendered_texture_id: Local<egui::TextureId>,
|
||||
mut is_initialized: Local<bool>,
|
||||
) {
|
||||
if !*is_initialized {
|
||||
*is_initialized = true;
|
||||
*rendered_texture_id = contexts.add_image(ui_assets.bar_handle.clone_weak());
|
||||
}
|
||||
|
||||
egui::CentralPanel::default().show(contexts.ctx_mut(), |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_width(60.0);
|
||||
ui.label("pokemon:");
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_width(150.0);
|
||||
ui.text_edit_singleline(&mut ui_state.name);
|
||||
});
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_width(60.0);
|
||||
ui.label("nature:");
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_width(150.0);
|
||||
ui.text_edit_singleline(&mut ui_state.nature);
|
||||
});
|
||||
});
|
||||
|
||||
if let Some(pokemon) = inspector.pokemon.as_ref() {
|
||||
ui.heading(egui::RichText::new(pokemon.name.clone()));
|
||||
|
||||
ui.label(format!(
|
||||
"{} / {}",
|
||||
pokemon.type1.as_ref().map_or("-", |t| t.name.as_str()),
|
||||
pokemon.type2.as_ref().map_or("-", |t| t.name.as_str())
|
||||
));
|
||||
|
||||
for stat in vec![
|
||||
BaseStat::Hp,
|
||||
BaseStat::Attack,
|
||||
BaseStat::Defense,
|
||||
BaseStat::SpecialAttack,
|
||||
BaseStat::SpecialDefense,
|
||||
BaseStat::Speed,
|
||||
] {
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_width(60.0);
|
||||
ui.label(format!("{stat}"));
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_width(8.0);
|
||||
let symbol = inspector.nature.as_ref().map_or("", |n| {
|
||||
if n.increased == Some(stat) {
|
||||
"+"
|
||||
} else if n.decreased == Some(stat) {
|
||||
"-"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
});
|
||||
ui.label(symbol);
|
||||
});
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_width(25.0);
|
||||
ui.label(pokemon.base_value(stat).to_string());
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
let base_value = pokemon.base_value(stat);
|
||||
let mut color = BASE_STAT_COLOR_RANGES.first().unwrap().1;
|
||||
for (treshold, c) in BASE_STAT_COLOR_RANGES.iter() {
|
||||
if base_value >= *treshold {
|
||||
color = c.clone();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let image =
|
||||
egui::Image::new(*rendered_texture_id, [base_value as f32, 12.])
|
||||
.tint(color);
|
||||
ui.set_width(260.0);
|
||||
ui.add(image);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue