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,
|
|
|
|
},
|
|
|
|
config::attributes::AttributeSettings,
|
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-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 09:22:59 +00:00
|
|
|
statistics.update(attributes, attribute_settings, &*items);
|
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)
|
|
|
|
}
|
|
|
|
}
|