rpg_base/character_window/src/abilities/ability_right_side.rs
2025-02-28 08:43:35 +01:00

273 lines
9.7 KiB
Rust

use std::marker::PhantomData;
use std::sync::{Arc, Weak};
use rpg_components::components::ability_slots::AbilitySlots;
use rpg_components::components::crafting_materials::CraftingMaterials;
use rpg_components::components::inventory::Storable;
use rpg_components::components::statistics::Statistics;
use rpg_components::config::items::ItemSettings;
use rpg_components::items::Rarities;
use crate::*;
use crate::{traits::RightSide, CharacterWindow};
pub struct AbilityPageRightSide<A: Ability + 'static> {
snippet: Arc<GuiSnippet>,
ability_index: usize,
ability_marker: PhantomData<A>,
}
impl<A: Ability + 'static> AbilityPageRightSide<A> {
const ABILITY_BUTTON_NAMES: [&'static str; 4] = [
"first_ability",
"second_ability",
"third_ability",
"fourth_ability",
];
pub fn new(
engine: &Arc<Engine>,
reference: &Weak<CharacterWindow>,
hero: Entity,
) -> Result<Self> {
let snippet = GuiSnippet::from_str(
engine.gui_handler(),
include_str!("../../resources/abilities/right_side.xml"),
)?;
let color_settings = &engine
.scene()
.resources
.get::<ItemSettings>()
.rarity_color_settings;
Self::rarity_icon_background(&snippet, "common", color_settings.common)?;
Self::rarity_icon_background(&snippet, "uncommon", color_settings.uncommon)?;
Self::rarity_icon_background(&snippet, "magical", color_settings.magical)?;
Self::rarity_icon_background(&snippet, "rare", color_settings.rare)?;
Self::rarity_icon_background(&snippet, "epic", color_settings.epic)?;
Self::rarity_icon_background(&snippet, "legendary", color_settings.legendary)?;
for (index, name) in Self::ABILITY_BUTTON_NAMES.iter().enumerate() {
let button: Arc<Button> = snippet.element(name)?;
button.set_info_icon(&engine.controller_icon(ControllerButton::RightStick)?)?;
button.set_callback({
let reference = reference.clone();
move || {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let abilities = tabs.abilities::<A>();
abilities.right_side.ability_index = index;
abilities.update_page()?;
}
Ok(())
}
});
button.set_select_callback({
let engine = engine.clone();
let reference = reference.clone();
let weak_button = Arc::downgrade(&button);
move |selected| {
if let Some(menu) = reference.upgrade() {
if selected {
engine.on_scene(|scene| {
let entity = scene.entity(hero)?;
let abilities = entity.get_component::<AbilitySlots<A>>()?;
if let Some(book) = abilities.book(index) {
let button = weak_button.upgrade().unwrap();
let button_pos = button.position_extent();
let target_x = button_pos.0 + button_pos.2 as i32;
let target_y = button_pos.1;
let statistics = entity.get_component::<Statistics>()?;
let gui = book.create_tooltip(
engine.gui_handler(),
statistics,
(target_x, target_y),
)?;
gui.enable()?;
gui.perform_single_check(button_pos.0, button_pos.1)?;
menu.add_tooltip("active_ability", gui);
}
Ok(())
})?;
} else {
menu.remove_tooltip("active_ability");
}
}
Ok(())
}
});
button.set_custom_callback({
let engine = engine.clone();
let reference = reference.clone();
move |button| match button {
ControllerButton::Y => {
engine.on_scene_mut(|scene| {
let entity = scene.entity_mut(hero)?;
let mut multi_mut = entity.multi_mut();
let abilities = multi_mut.get::<AbilitySlots<A>>()?;
if let Some(ability) = abilities.book_mut(index) {
let materials = multi_mut.get::<CraftingMaterials>()?;
ability.upgrade(materials);
if let Some(menu) = reference.upgrade() {
menu.tabs_mut()
.abilities::<A>()
.right_side
.refresh(&engine, hero)?;
}
}
Ok(())
})?;
Ok(true)
}
_ => Ok(false),
}
})
}
Ok(Self {
snippet,
ability_index: 0,
ability_marker: PhantomData,
})
}
pub fn selected_ability(&self) -> usize {
self.ability_index
}
fn rarity_icon_background(gui: &GuiSnippet, element: &str, color: Color) -> Result<()> {
let icon: Arc<Icon> = gui.element(element)?;
icon.set_background(FillTypeInfo::Element(
ElementDescriptor::new(color, Color::Black, 2),
DisplayableFillType::Square,
))
}
fn update_crafting_count(&self, element: &str, value: u32) -> Result<()> {
let icon: Arc<Icon> = self.snippet.element(element)?;
icon.set_text(value)?;
Ok(())
}
fn update_ability_icon(&self, element: &str, image: Option<Arc<Image>>) -> Result<()> {
let button: Arc<Button> = self.snippet.element(element)?;
match image {
Some(image) => {
button.set_icon(&image)?;
}
None => {
button.clear_icon()?;
}
}
Ok(())
}
fn update_active_ability(&self, engine: &Engine, abilities: &AbilitySlots<A>) -> Result<()> {
let grid: Arc<Grid> = self.snippet.element("ability_content")?;
let (_, rows) = grid.dimensions();
for y in 0..rows {
grid.detach(0, y)?;
}
if let Some(ability) = abilities.book(self.ability_index) {
for (index, addon) in ability.addons().iter().enumerate() {
match addon.as_ref() {
Some(addon) => {
let addon_type_snippet = GuiSnippet::from_str(
engine.gui_handler(),
include_str!("../../resources/abilities/addon_type_snippet.xml"),
)?;
let addon_icon: Arc<Icon> = addon_type_snippet.element("addon_icon")?;
let addon_type: Arc<Label> = addon_type_snippet.element("addon_type")?;
let addon_value: Arc<Label> = addon_type_snippet.element("addon_value")?;
addon_icon.set_icon(&addon.icon())?;
addon_type.set_text(&format!("{}", addon.addon_type()))?;
addon_value.set_text(&addon.addon_type().val_as_str())?;
grid.attach(addon_type_snippet, 0, index, 1, 1)?;
}
None => {
let empty_addon = GuiSnippet::from_str(
engine.gui_handler(),
include_str!("../../resources/abilities/empty_addon_snippet.xml"),
)?;
grid.attach(empty_addon, 0, index, 1, 1)?;
}
}
}
}
Ok(())
}
pub fn next_ability(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()> {
self.ability_index = (self.ability_index + 1) % 4;
self.refresh(engine, hero)
}
}
impl<A: Ability + 'static> RightSide for AbilityPageRightSide<A> {
fn refresh(&mut self, engine: &Engine, hero: Entity) -> Result<()> {
engine.on_scene(|scene| {
let entity = scene.entity(hero)?;
let crafting = entity.get_component::<CraftingMaterials>()?;
self.update_crafting_count("common", crafting.count(Rarities::Common))?;
self.update_crafting_count("uncommon", crafting.count(Rarities::Uncommon))?;
self.update_crafting_count("magical", crafting.count(Rarities::Magical))?;
self.update_crafting_count("rare", crafting.count(Rarities::Rare))?;
self.update_crafting_count("epic", crafting.count(Rarities::Epic))?;
self.update_crafting_count("legendary", crafting.count(Rarities::Legendary))?;
let abilities = entity.get_component::<AbilitySlots<A>>()?;
for (index, name) in Self::ABILITY_BUTTON_NAMES.iter().enumerate() {
self.update_ability_icon(name, abilities.book(index).map(|book| book.icon()))?;
}
self.update_active_ability(engine, abilities)?;
Ok(())
})
}
fn base(&self) -> &Arc<GuiSnippet> {
&self.snippet
}
}