engine/character_window/src/character/mod.rs

272 lines
8.7 KiB
Rust
Raw Normal View History

2024-08-25 12:30:03 +00:00
use std::sync::{Arc, Weak};
use anyhow::Result;
2024-08-26 09:22:59 +00:00
use rpg_components::{
components::{
attributes::{Agility, Attributes, Intelligence, Strength},
item_slots::ItemSlotContainer,
level::Level,
statistics::Statistics,
},
2024-08-26 11:29:24 +00:00
config::{attributes::AttributeSettings, items::ItemSettings},
2024-08-25 12:30:03 +00:00
};
use super::{CharacterWindow, Page};
use crate::*;
pub struct CharacterPage {
engine: Arc<Engine>,
hero: Entity,
snippet: Arc<GuiSnippet>,
grid: Arc<Grid>,
}
impl CharacterPage {
pub fn new(
engine: &Arc<Engine>,
hero: Entity,
hero_name: &str,
reference: &Weak<CharacterWindow>,
) -> Result<Self> {
let snippet = GuiSnippet::from_str(
engine.gui_handler(),
2024-08-26 08:08:03 +00:00
include_str!("../../resources/character/statistics.xml"),
2024-08-25 12:30:03 +00:00
)?;
let grid: Arc<Grid> = snippet.element("statistic_tab")?;
let name: Arc<Label> = snippet.element("character_name")?;
name.set_text(hero_name)?;
let strength: Arc<Button> = snippet.element("strength_field")?;
strength.set_callback({
2024-08-26 08:08:03 +00:00
let update_stats = Self::create_update_stats(hero, engine, reference);
2024-08-25 12:30:03 +00:00
move || {
update_stats(|attributes| {
attributes.add_strength(Strength::from(1));
})
}
});
let agility: Arc<Button> = snippet.element("agility_field")?;
agility.set_callback({
2024-08-26 08:08:03 +00:00
let update_stats = Self::create_update_stats(hero, engine, reference);
2024-08-25 12:30:03 +00:00
move || {
update_stats(|attributes| {
attributes.add_agility(Agility::from(1));
})
}
});
let intelligence: Arc<Button> = snippet.element("intelligence_field")?;
intelligence.set_callback({
2024-08-26 08:08:03 +00:00
let update_stats = Self::create_update_stats(hero, engine, reference);
2024-08-25 12:30:03 +00:00
move || {
update_stats(|attributes| {
attributes.add_intelligence(Intelligence::from(1));
})
}
});
Ok(Self {
2024-08-26 08:08:03 +00:00
engine: engine.clone(),
2024-08-25 12:30:03 +00:00
hero,
snippet,
grid,
})
}
fn refresh(&self) -> Result<()> {
self.update_stats()?;
self.update_attributes()?;
Ok(())
}
fn update_stats(&self) -> Result<()> {
let air_def: Arc<Label> = self.snippet.element("air_def_info")?;
let fire_def: Arc<Label> = self.snippet.element("fire_def_info")?;
let water_def: Arc<Label> = self.snippet.element("water_def_info")?;
let armor: Arc<Label> = self.snippet.element("armor_info")?;
let air_dmg: Arc<Label> = self.snippet.element("air_dmg_info")?;
let fire_dmg: Arc<Label> = self.snippet.element("fire_dmg_info")?;
let water_dmg: Arc<Label> = self.snippet.element("water_dmg_info")?;
let phys_dmg: Arc<Label> = self.snippet.element("phys_dmg_info")?;
let crit_chance: Arc<Label> = self.snippet.element("crit_chance_info")?;
let crit_dmg: Arc<Label> = self.snippet.element("crit_dmg_info")?;
let health: Arc<Label> = self.snippet.element("health_info")?;
let health_regen: Arc<Label> = self.snippet.element("health_regen_info")?;
let mana: Arc<Label> = self.snippet.element("mana_info")?;
let mana_regen: Arc<Label> = self.snippet.element("mana_regen_info")?;
self.engine.on_scene(|scene| {
let entity = scene.entity(self.hero)?;
let statistics = entity.get_component::<Statistics>()?;
air_def.set_text(&format!("{}", statistics.air_resistance.raw()))?;
fire_def.set_text(&format!("{}", statistics.fire_resistance.raw()))?;
water_def.set_text(&format!("{}", statistics.water_resistance.raw()))?;
armor.set_text(&format!("{}", statistics.armor.raw()))?;
air_dmg.set_text(&format!("{}", statistics.air_damage.raw()))?;
fire_dmg.set_text(&format!("{}", statistics.fire_damage.raw()))?;
water_dmg.set_text(&format!("{}", statistics.water_damage.raw()))?;
phys_dmg.set_text(&format!("{}", statistics.physical_damage.raw()))?;
crit_chance.set_text(&format!("{:.2} %", statistics.critical_hit_chance.raw()))?;
crit_dmg.set_text(&format!(
"{:.2} %",
statistics.critical_hit_damage.raw() + 100.0
))?;
health.set_text(&format!("{:.0}", statistics.health.raw()))?;
health_regen.set_text(&format!("{:.2}", statistics.health_regeneration.raw()))?;
mana.set_text(&format!("{:.0}", statistics.mana.raw()))?;
mana_regen.set_text(&format!("{:.2}", statistics.mana_regeneration.raw()))?;
Ok(())
})
}
fn update_attributes(&self) -> Result<()> {
let level_label: Arc<Label> = self.snippet.element("level")?;
let level_progress: Arc<ProgressBar> = self.snippet.element("level_progress")?;
let attributes_label: Arc<Label> = self.snippet.element("attributes")?;
let strength: Arc<Button> = self.snippet.element("strength_field")?;
let agility: Arc<Button> = self.snippet.element("agility_field")?;
let intelligence: Arc<Button> = self.snippet.element("intelligence_field")?;
self.engine.on_scene(|scene| {
let entity = scene.entity(self.hero)?;
let level = entity.get_component::<Level>()?;
let attributes = entity.get_component::<Attributes>()?;
level_label.set_text(format!("Level: {}", level.level()))?;
level_progress.set_text(format!(
"{} / {}",
level.current_experience, level.experience_needed
))?;
attributes_label.set_text(format!(
"Attributes ({})",
2024-08-26 09:22:59 +00:00
Self::available_attribute_points(
&scene.resources.get::<AttributeSettings>(),
attributes,
level
)
2024-08-25 12:30:03 +00:00
))?;
strength.set_text(attributes.strength().raw())?;
agility.set_text(attributes.agility().raw())?;
intelligence.set_text(attributes.intelligence().raw())?;
Ok(())
})
}
2024-08-26 08:08:03 +00:00
fn available_attribute_points(
2024-08-26 09:22:59 +00:00
settings: &AttributeSettings,
2024-08-26 08:08:03 +00:00
attributes: &Attributes,
level: &Level,
) -> u32 {
2024-08-26 09:22:59 +00:00
let total_attribute_points = settings.meta_settings.starting_skill_points
+ level.level() * settings.meta_settings.skill_points_per_level
+ settings.starting_attributes.sum();
2024-08-25 12:30:03 +00:00
let attributes_spent = attributes.sum();
total_attribute_points - attributes_spent
}
fn create_update_stats<F>(
hero: Entity,
engine: &Arc<Engine>,
reference: &Weak<CharacterWindow>,
) -> impl Fn(F) -> Result<()> + Clone
where
F: Fn(&mut Attributes),
{
let engine = engine.clone();
let reference = reference.clone();
move |upgrade: F| {
let mut upgraded = false;
engine.on_scene_mut(|scene| {
2024-08-26 09:22:59 +00:00
let (resources, entity) = scene.entity_resource(hero)?;
2024-08-25 12:30:03 +00:00
let mut multi_mut = entity.multi_mut();
2024-08-26 09:22:59 +00:00
let attribute_settings = resources.get::<AttributeSettings>();
2024-08-26 11:29:24 +00:00
let item_settings = resources.get::<ItemSettings>();
2024-08-26 09:22:59 +00:00
2024-08-25 12:30:03 +00:00
let level = multi_mut.get::<Level>()?;
let attributes = multi_mut.get::<Attributes>()?;
2024-08-26 09:22:59 +00:00
if Self::available_attribute_points(attribute_settings, attributes, level) > 0 {
2024-08-25 12:30:03 +00:00
upgrade(attributes);
let statistics = multi_mut.get::<Statistics>()?;
let items = multi_mut.get::<ItemSlotContainer>()?;
2024-08-26 11:29:24 +00:00
statistics.update(attributes, attribute_settings, (&*items, item_settings));
2024-08-25 12:30:03 +00:00
upgraded = true;
}
Ok(())
})?;
if upgraded {
if let Some(menu) = reference.upgrade() {
menu.tabs().character().refresh()?;
}
}
Ok(())
}
}
}
impl Page for CharacterPage {
fn enable(&mut self) -> Result<Arc<Grid>> {
println!("enable CharacterPage");
self.refresh()?;
Ok(self.grid.clone())
}
fn disable(&mut self) -> Result<()> {
Ok(())
}
fn select(&self) -> Result<()> {
let strength: Arc<Button> = self.snippet.element("strength_field")?;
strength.select()?;
Ok(())
}
fn next_tab(&mut self) -> Result<()> {
Ok(())
}
fn previous_tab(&mut self) -> Result<()> {
Ok(())
}
fn event(&mut self, _button: ControllerButton) -> Result<bool> {
Ok(false)
}
}