2025-02-28 07:43:35 +00:00
|
|
|
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::*;
|
|
|
|
|
2025-03-04 17:40:56 +00:00
|
|
|
use crate::{CharacterWindow, traits::RightSide};
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
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",
|
|
|
|
];
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
pub fn new(world: &mut World, hero: Entity, reference: &Weak<CharacterWindow>) -> Result<Self> {
|
2025-02-28 07:43:35 +00:00
|
|
|
let snippet = GuiSnippet::from_str(
|
2025-03-05 09:31:16 +00:00
|
|
|
world,
|
2025-02-28 07:43:35 +00:00
|
|
|
include_str!("../../resources/abilities/right_side.xml"),
|
|
|
|
)?;
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
let color_settings = world
|
|
|
|
.resources
|
2025-03-05 09:31:16 +00:00
|
|
|
.get::<ItemSettings>()
|
|
|
|
.rarity_color_settings
|
|
|
|
.clone();
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
let (gui_handler, engine_settings, context): (
|
|
|
|
&mut GuiHandler,
|
|
|
|
&mut EngineSettings,
|
|
|
|
&mut Context,
|
|
|
|
) = world.resources.get_mut()?;
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
Self::rarity_icon_background(gui_handler, &snippet, "common", color_settings.common)?;
|
|
|
|
Self::rarity_icon_background(gui_handler, &snippet, "uncommon", color_settings.uncommon)?;
|
|
|
|
Self::rarity_icon_background(gui_handler, &snippet, "magical", color_settings.magical)?;
|
|
|
|
Self::rarity_icon_background(gui_handler, &snippet, "rare", color_settings.rare)?;
|
|
|
|
Self::rarity_icon_background(gui_handler, &snippet, "epic", color_settings.epic)?;
|
|
|
|
Self::rarity_icon_background(gui_handler, &snippet, "legendary", color_settings.legendary)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
for (index, name) in Self::ABILITY_BUTTON_NAMES.iter().enumerate() {
|
|
|
|
let button: Arc<Button> = snippet.element(name)?;
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
button.set_info_icon(
|
|
|
|
gui_handler,
|
|
|
|
&engine_settings.controller_icon(context, ControllerButton::RightStick)?,
|
|
|
|
)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
button.set_callback({
|
2025-03-05 09:31:16 +00:00
|
|
|
let reference = reference.clone();
|
|
|
|
|
|
|
|
move |world: &mut World| {
|
2025-02-28 07:43:35 +00:00
|
|
|
if let Some(menu) = reference.upgrade() {
|
|
|
|
let mut tabs = menu.tabs_mut();
|
|
|
|
let abilities = tabs.abilities::<A>();
|
|
|
|
|
|
|
|
abilities.right_side.ability_index = index;
|
2025-03-05 09:31:16 +00:00
|
|
|
abilities.update_page(world)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
button.set_select_callback({
|
|
|
|
let reference = reference.clone();
|
|
|
|
let weak_button = Arc::downgrade(&button);
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
move |world, selected| {
|
2025-02-28 07:43:35 +00:00
|
|
|
if let Some(menu) = reference.upgrade() {
|
|
|
|
if selected {
|
2025-03-05 09:31:16 +00:00
|
|
|
let entity = unsafe { remove_life_time(world.entity(hero)?) };
|
|
|
|
let abilities = entity.get_component::<AbilitySlots<A>>()?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
if let Some(book) = abilities.book(index) {
|
|
|
|
let button = weak_button.upgrade().unwrap();
|
|
|
|
let button_pos = button.position_extent();
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
let target_x = button_pos.0 + button_pos.2 as i32;
|
|
|
|
let target_y = button_pos.1;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
let statistics = entity.get_component::<Statistics>()?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
let gui =
|
|
|
|
book.create_tooltip(world, statistics, (target_x, target_y))?;
|
|
|
|
gui.enable(world)?;
|
|
|
|
gui.perform_single_check(
|
2025-04-05 10:16:34 +00:00
|
|
|
world.resources.get_mut()?,
|
2025-03-05 09:31:16 +00:00
|
|
|
button_pos.0,
|
|
|
|
button_pos.1,
|
|
|
|
)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
menu.add_tooltip("active_ability", gui);
|
|
|
|
}
|
2025-02-28 07:43:35 +00:00
|
|
|
} else {
|
2025-03-06 16:30:50 +00:00
|
|
|
menu.remove_tooltip(world, "active_ability")?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
button.set_custom_callback({
|
|
|
|
let reference = reference.clone();
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
move |world, button| match button {
|
2025-02-28 07:43:35 +00:00
|
|
|
ControllerButton::Y => {
|
2025-03-05 09:31:16 +00:00
|
|
|
let entity = world.entity_mut(hero)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-04-05 11:45:08 +00:00
|
|
|
let (abilities, materials): (&mut AbilitySlots<A>, &mut CraftingMaterials) =
|
|
|
|
entity.get_components_mut()?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
if let Some(ability) = abilities.book_mut(index) {
|
|
|
|
ability.upgrade(materials);
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
if let Some(menu) = reference.upgrade() {
|
|
|
|
menu.tabs_mut()
|
|
|
|
.abilities::<A>()
|
|
|
|
.right_side
|
|
|
|
.refresh(world, hero)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
2025-03-05 09:31:16 +00:00
|
|
|
}
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => Ok(false),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
snippet,
|
|
|
|
ability_index: 0,
|
|
|
|
ability_marker: PhantomData,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn selected_ability(&self) -> usize {
|
|
|
|
self.ability_index
|
|
|
|
}
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
fn rarity_icon_background(
|
|
|
|
gui_handler: &mut GuiHandler,
|
|
|
|
gui: &GuiSnippet,
|
|
|
|
element: &str,
|
|
|
|
color: Color,
|
|
|
|
) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
let icon: Arc<Icon> = gui.element(element)?;
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
icon.set_background(
|
|
|
|
gui_handler,
|
|
|
|
FillTypeInfo::Element(
|
|
|
|
ElementDescriptor::new(color, Color::Black, 2),
|
|
|
|
DisplayableFillType::Square,
|
|
|
|
),
|
|
|
|
)
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
fn update_crafting_count(
|
|
|
|
&self,
|
|
|
|
gui_handler: &mut GuiHandler,
|
|
|
|
element: &str,
|
|
|
|
value: u32,
|
|
|
|
) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
let icon: Arc<Icon> = self.snippet.element(element)?;
|
2025-03-05 09:31:16 +00:00
|
|
|
icon.set_text(gui_handler, value)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
fn update_ability_icon(
|
|
|
|
&self,
|
|
|
|
gui_handler: &mut GuiHandler,
|
|
|
|
element: &str,
|
|
|
|
image: Option<Arc<Image>>,
|
|
|
|
) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
let button: Arc<Button> = self.snippet.element(element)?;
|
|
|
|
|
|
|
|
match image {
|
|
|
|
Some(image) => {
|
2025-03-05 09:31:16 +00:00
|
|
|
button.set_icon(gui_handler, &image)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
None => {
|
2025-03-05 09:31:16 +00:00
|
|
|
button.clear_icon(gui_handler)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
fn update_active_ability(&self, world: &mut World, abilities: &AbilitySlots<A>) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
let grid: Arc<Grid> = self.snippet.element("ability_content")?;
|
|
|
|
let (_, rows) = grid.dimensions();
|
|
|
|
|
|
|
|
for y in 0..rows {
|
2025-03-05 09:31:16 +00:00
|
|
|
grid.detach(world, 0, y)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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(
|
2025-03-05 09:31:16 +00:00
|
|
|
world,
|
2025-02-28 07:43:35 +00:00
|
|
|
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")?;
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
let gui_handler: &mut GuiHandler = world.resources.get_mut()?;
|
2025-03-05 09:31:16 +00:00
|
|
|
|
|
|
|
addon_icon.set_icon(gui_handler, &addon.icon())?;
|
|
|
|
addon_type.set_text(gui_handler, &format!("{}", addon.addon_type()))?;
|
|
|
|
addon_value.set_text(gui_handler, &addon.addon_type().val_as_str())?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
grid.attach(world, addon_type_snippet, 0, index, 1, 1)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let empty_addon = GuiSnippet::from_str(
|
2025-03-05 09:31:16 +00:00
|
|
|
world,
|
2025-02-28 07:43:35 +00:00
|
|
|
include_str!("../../resources/abilities/empty_addon_snippet.xml"),
|
|
|
|
)?;
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
grid.attach(world, empty_addon, 0, index, 1, 1)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
pub fn next_ability(&mut self, world: &mut World, hero: Entity) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.ability_index = (self.ability_index + 1) % 4;
|
2025-03-05 09:31:16 +00:00
|
|
|
self.refresh(world, hero)
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<A: Ability + 'static> RightSide for AbilityPageRightSide<A> {
|
2025-03-05 09:31:16 +00:00
|
|
|
fn refresh(&mut self, world: &mut World, hero: Entity) -> Result<()> {
|
|
|
|
let entity = unsafe { remove_life_time(world.entity(hero)?) };
|
|
|
|
|
|
|
|
let crafting = entity.get_component::<CraftingMaterials>()?;
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
let gui_handler: &mut GuiHandler = world.resources.get_mut()?;
|
2025-03-05 09:31:16 +00:00
|
|
|
|
|
|
|
self.update_crafting_count(gui_handler, "common", crafting.count(Rarities::Common))?;
|
|
|
|
self.update_crafting_count(gui_handler, "uncommon", crafting.count(Rarities::Uncommon))?;
|
|
|
|
self.update_crafting_count(gui_handler, "magical", crafting.count(Rarities::Magical))?;
|
|
|
|
self.update_crafting_count(gui_handler, "rare", crafting.count(Rarities::Rare))?;
|
|
|
|
self.update_crafting_count(gui_handler, "epic", crafting.count(Rarities::Epic))?;
|
|
|
|
self.update_crafting_count(
|
|
|
|
gui_handler,
|
|
|
|
"legendary",
|
|
|
|
crafting.count(Rarities::Legendary),
|
|
|
|
)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
let abilities = entity.get_component::<AbilitySlots<A>>()?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
for (index, name) in Self::ABILITY_BUTTON_NAMES.iter().enumerate() {
|
|
|
|
self.update_ability_icon(
|
|
|
|
gui_handler,
|
|
|
|
name,
|
|
|
|
abilities.book(index).map(|book| book.icon()),
|
|
|
|
)?;
|
|
|
|
}
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
self.update_active_ability(world, abilities)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
2025-03-05 09:31:16 +00:00
|
|
|
Ok(())
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn base(&self) -> &Arc<GuiSnippet> {
|
|
|
|
&self.snippet
|
|
|
|
}
|
|
|
|
}
|