khguide/src/common/materials.rs

237 lines
6.2 KiB
Rust

use std::{collections::HashMap, fmt::Display, fs, path};
use serde::Deserialize;
use crate::ASSETS_FOLDER_PATH;
use super::{
Game,
enemy::{Enemy, EnemyDrop},
};
pub const GENERIC_MATERIAL_ICON: &str = "generic";
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct MaterialDetails {
pub category: MaterialCategory,
pub kind: MaterialKind,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "lowercase")]
pub enum MaterialCategory {
// Common
#[serde(alias = "blaze")]
Blazing,
#[serde(alias = "soothing")]
Bright,
#[serde(alias = "betwixt")]
Dense,
#[serde(alias = "writhing")]
Dark,
#[serde(alias = "wellspring")]
Energy,
Frost,
#[serde(alias = "thunder")]
Lightning,
Lucid,
Mythril,
Orichalcum,
Power,
#[serde(alias = "shiny")]
Shimmering,
#[serde(alias = "mystery", alias = "hungry")]
Serenity,
Twilight,
// KH1 Only
Spirit,
Stormy,
// KH2 Only
Remembrance,
}
impl MaterialCategory {
pub fn get_texture_group(&self) -> String {
match self {
MaterialCategory::Blazing => "blazing".to_string(),
MaterialCategory::Bright => "bright".to_string(),
MaterialCategory::Dense => "dense".to_string(),
MaterialCategory::Dark => "dark".to_string(),
MaterialCategory::Energy => "energy".to_string(),
MaterialCategory::Frost => "frost".to_string(),
MaterialCategory::Lightning => "lightning".to_string(),
MaterialCategory::Lucid => "lucid".to_string(),
MaterialCategory::Mythril => "mythril".to_string(),
MaterialCategory::Orichalcum => "orichalcum".to_string(),
MaterialCategory::Power => "power".to_string(),
MaterialCategory::Shimmering => "shimmering".to_string(),
MaterialCategory::Serenity => "serenity".to_string(),
MaterialCategory::Twilight => "twilight".to_string(),
MaterialCategory::Spirit => "spirit".to_string(),
MaterialCategory::Stormy => "stormy".to_string(),
MaterialCategory::Remembrance => "remembrance".to_string(),
}
}
pub fn get_category(&self, game: &Game) -> String {
match self {
MaterialCategory::Blazing => match game {
Game::Kh1 => "blaze".to_string(),
_ => "blazing".to_string(),
},
MaterialCategory::Bright => match game {
Game::Kh1 | Game::Kh2 => "bright".to_string(),
_ => "soothing".to_string(),
},
MaterialCategory::Dense => match game {
Game::Kh2 => "dense".to_string(),
_ => "betwixt".to_string(),
},
MaterialCategory::Dark => match game {
Game::Kh2 => "dark".to_string(),
_ => "writhing".to_string(),
},
MaterialCategory::Energy => match game {
Game::Kh1 | Game::Kh2 => "energy".to_string(),
_ => "wellspring".to_string(),
},
MaterialCategory::Frost => "frost".to_string(),
MaterialCategory::Lightning => match game {
Game::Kh1 => "thunder".to_string(),
_ => "lightning".to_string(),
},
MaterialCategory::Lucid => "lucid".to_string(),
MaterialCategory::Mythril => "mythril".to_string(),
MaterialCategory::Orichalcum => "orichalcum".to_string(),
MaterialCategory::Power => "power".to_string(),
MaterialCategory::Shimmering => match game {
Game::Kh1 => "shiny".to_string(),
_ => "shimmering".to_string(),
},
MaterialCategory::Serenity => match game {
Game::Kh1 => "mystery".to_string(),
Game::Bbs => "hungry".to_string(),
_ => "serenity".to_string(),
},
MaterialCategory::Twilight => "twilight".to_string(),
MaterialCategory::Spirit => "spirit".to_string(),
MaterialCategory::Stormy => "stormy".to_string(),
MaterialCategory::Remembrance => "remembrance".to_string(),
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(rename_all = "lowercase")]
pub enum MaterialKind {
Shard,
Stone,
Gem,
Crystal,
}
impl Display for MaterialKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MaterialKind::Shard => f.write_str("shard"),
MaterialKind::Stone => f.write_str("stone"),
MaterialKind::Gem => f.write_str("gem"),
MaterialKind::Crystal => f.write_str("crystal"),
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct MaterialDrops {
pub name: String,
pub icon: String,
pub category: MaterialCategory,
pub kind: MaterialKind,
pub drops: Vec<EnemyDrop>,
}
impl PartialOrd for MaterialDrops {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.category.cmp(&other.category) == std::cmp::Ordering::Equal {
return Some(self.kind.cmp(&other.kind));
}
Some(self.category.cmp(&other.category))
}
}
impl MaterialDrops {
pub fn new(enemies: Vec<Enemy>) -> Vec<MaterialDrops> {
let mut mat_map = HashMap::<(MaterialCategory, MaterialKind), MaterialDrops>::new();
for enemy in enemies {
for drop in &enemy.drops {
let Some(material) = &drop.material else {
continue;
};
let key = (material.category.clone(), material.kind.clone());
mat_map
.entry(key)
.and_modify(|d| d.drops.push(drop.clone()))
.or_insert(MaterialDrops {
name: drop.name.to_string(),
icon: "".to_string(),
category: material.category.clone(),
kind: material.kind.clone(),
drops: vec![drop.clone()],
});
}
}
let mut values: Vec<MaterialDrops> = mat_map.into_values().collect();
values.sort_by(|a, b| a.partial_cmp(b).unwrap());
values
}
pub fn drops(&self, kind: &str) -> Vec<&EnemyDrop> {
match kind {
"shard" => self.get_drop_kind(MaterialKind::Shard),
"stone" => self.get_drop_kind(MaterialKind::Stone),
"gem" => self.get_drop_kind(MaterialKind::Gem),
"crystal" => self.get_drop_kind(MaterialKind::Crystal),
_ => vec![],
}
}
fn get_drop_kind(&self, kind: MaterialKind) -> Vec<&EnemyDrop> {
self.drops
.iter()
.filter(|d| d.material.as_ref().map(|m| m.kind == kind).unwrap_or(false))
.collect::<Vec<&EnemyDrop>>()
}
pub fn texture(&self, game: &Game) -> String {
if *game == Game::Kh1 {
return GENERIC_MATERIAL_ICON.to_string();
}
let category = self.category.get_category(game);
let kind = self.kind.to_string();
let path = format!(
"{}/materials/{}/{}.webp",
ASSETS_FOLDER_PATH, category, kind
);
let path = path::Path::new(&path);
if path.exists() {
format!("{}/{}", self.category.get_category(game), self.kind)
} else {
GENERIC_MATERIAL_ICON.to_string()
}
}
}