rpg_base/character_window/src/inventory/item_right_side.rs

488 lines
18 KiB
Rust
Raw Normal View History

2025-03-05 08:45:39 +00:00
use anyhow::Result;
use assetpath::AssetPath;
2025-02-28 07:43:35 +00:00
use rpg_components::{
components::{
attributes::Attributes, character_status::CharacterStatus, inventory::Inventory,
item_slots::ItemSlotContainer, statistics::Statistics,
},
config::{attributes::AttributeSettings, items::ItemSettings},
items::{Item, ItemAffix, Tooltip},
};
use crate::*;
use std::sync::{Arc, Weak};
use super::{
super::traits::*,
jewel_right_side::{ReferenceItemSource, ReferenceObject},
};
pub struct ItemRightSide {
snippet: Arc<GuiSnippet>,
empty_icons: InventoryEmptyIcons,
}
impl ItemRightSide {
pub fn new<A: Ability + 'static>(
2025-03-05 08:45:39 +00:00
world: &mut World,
2025-02-28 07:43:35 +00:00
file: &str,
reference: &Weak<CharacterWindow>,
hero: Entity,
) -> Result<Self> {
2025-03-05 08:45:39 +00:00
let snippet = GuiSnippet::from_str(world, file)?;
let icons = InventoryEmptyIcons::new(world)?;
2025-02-28 07:43:35 +00:00
let me = Self {
snippet,
empty_icons: icons,
};
2025-03-05 08:45:39 +00:00
me.setup::<A>(reference, hero)?;
2025-02-28 07:43:35 +00:00
Ok(me)
}
fn setup<A: Ability + 'static>(
&self,
reference: &Weak<CharacterWindow>,
hero: Entity,
) -> Result<()> {
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, helmet, "helmet");
button_setup!(self, reference, hero, chest, "chest");
button_setup!(self, reference, hero, gloves, "gloves");
button_setup!(self, reference, hero, belt, "belt");
button_setup!(self, reference, hero, boots, "boots");
2025-02-28 07:43:35 +00:00
#[rustfmt::skip]
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, primary_hand, "main hand");
2025-02-28 07:43:35 +00:00
#[rustfmt::skip]
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, secondary_hand, "off hand");
2025-02-28 07:43:35 +00:00
#[rustfmt::skip]
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, amulet, "amulet_0", 0);
2025-02-28 07:43:35 +00:00
#[rustfmt::skip]
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, amulet, "amulet_1", 1);
2025-02-28 07:43:35 +00:00
#[rustfmt::skip]
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, ring, "ring_0", 0);
2025-02-28 07:43:35 +00:00
#[rustfmt::skip]
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, ring, "ring_1", 1);
2025-02-28 07:43:35 +00:00
#[rustfmt::skip]
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, ring, "ring_2", 2);
2025-02-28 07:43:35 +00:00
#[rustfmt::skip]
2025-03-05 08:45:39 +00:00
button_setup!(self, reference, hero, ring, "ring_3", 3);
2025-02-28 07:43:35 +00:00
Ok(())
}
2025-03-05 08:45:39 +00:00
fn update_icons(&self, gui_handler: &mut GuiHandler, items: &ItemSlotContainer) -> Result<()> {
2025-02-28 07:43:35 +00:00
let ui = &self.snippet;
let empty_icons = &self.empty_icons;
2025-03-05 08:45:39 +00:00
equip_update!(ui, gui_handler, items, helmet, empty_icons);
equip_update!(ui, gui_handler, items, chest, empty_icons);
equip_update!(ui, gui_handler, items, boots, empty_icons);
equip_update!(ui, gui_handler, items, gloves, empty_icons);
equip_update!(ui, gui_handler, items, belt, empty_icons);
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
#[rustfmt::skip]
equip_update!(ui,gui_handler, items, primary_hand, empty_icons, "main hand");
#[rustfmt::skip]
equip_update!(ui, gui_handler,items, secondary_hand, empty_icons, "off hand");
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
equip_update!(ui, gui_handler, items, ring, empty_icons, "ring_0", 0);
equip_update!(ui, gui_handler, items, ring, empty_icons, "ring_1", 1);
equip_update!(ui, gui_handler, items, ring, empty_icons, "ring_2", 2);
equip_update!(ui, gui_handler, items, ring, empty_icons, "ring_3", 3);
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
equip_update!(ui, gui_handler, items, amulet, empty_icons, "amulet_0", 0);
equip_update!(ui, gui_handler, items, amulet, empty_icons, "amulet_1", 1);
2025-02-28 07:43:35 +00:00
Ok(())
}
fn create_tooltip(
2025-03-05 08:45:39 +00:00
world: &mut World,
2025-02-28 07:43:35 +00:00
item: &Item,
attributes: &Attributes,
(x, y, w, _h): (i32, i32, u32, u32),
) -> Result<Tooltip> {
let target_x = x + w as i32;
let target_y = y;
2025-03-05 08:45:39 +00:00
let gui = item.create_tooltip(world, attributes, (target_x, target_y))?;
gui.enable(world)?;
2025-04-05 11:45:08 +00:00
gui.perform_single_check(world.resources.get_mut()?, x, y)?;
2025-02-28 07:43:35 +00:00
Ok(gui)
}
}
impl RightSide for ItemRightSide {
2025-03-05 08:45:39 +00:00
fn refresh(&mut self, world: &mut World, hero: Entity) -> Result<()> {
let (hero_object, resources) = world.entity_resources(hero)?;
let items = hero_object.get_component::<ItemSlotContainer>()?;
2025-02-28 07:43:35 +00:00
2025-04-05 11:45:08 +00:00
self.update_icons(resources.get_mut()?, items)
2025-02-28 07:43:35 +00:00
}
fn base(&self) -> &Arc<GuiSnippet> {
&self.snippet
}
}
struct InventoryEmptyIcons {
helmet: Arc<Image>,
chest: Arc<Image>,
belt: Arc<Image>,
boots: Arc<Image>,
gloves: Arc<Image>,
primary_hand: Arc<Image>,
secondary_hand: Arc<Image>,
ring: Arc<Image>,
amulet: Arc<Image>,
}
impl InventoryEmptyIcons {
2025-03-05 08:45:39 +00:00
fn new(world: &World) -> Result<Self> {
let place_holder_settings = &world
2025-02-28 07:43:35 +00:00
.resources
.get::<ItemSettings>()
.icon_place_holder_paths;
2025-03-05 08:45:39 +00:00
let context = world.resources.get::<Context>();
2025-02-28 07:43:35 +00:00
Ok(Self {
2025-03-05 08:45:39 +00:00
helmet: Self::image(context, &place_holder_settings.helmet)?,
chest: Self::image(context, &place_holder_settings.chest)?,
belt: Self::image(context, &place_holder_settings.belt)?,
boots: Self::image(context, &place_holder_settings.boots)?,
gloves: Self::image(context, &place_holder_settings.gloves)?,
primary_hand: Self::image(context, &place_holder_settings.main_hand)?,
secondary_hand: Self::image(context, &place_holder_settings.off_hand)?,
ring: Self::image(context, &place_holder_settings.ring)?,
amulet: Self::image(context, &place_holder_settings.amulet)?,
2025-02-28 07:43:35 +00:00
})
}
2025-03-05 08:45:39 +00:00
fn image(context: &Context, path: &AssetPath) -> Result<Arc<Image>> {
Image::from_file(path.clone())?
.max_mip_map_levels()
.attach_pretty_sampler(context.device())?
.build(context.device(), context.queue())
}
2025-02-28 07:43:35 +00:00
}
mod macros {
#[macro_export]
macro_rules! button_setup {
2025-03-05 08:45:39 +00:00
($self:ident, $reference:ident, $hero:ident, $item:ident, $button:literal) => {
2025-02-28 07:43:35 +00:00
paste::expr! {
let [<$item _button>]: Arc<Button> = $self.snippet.element($button)?;
[<$item _button>].set_select_callback({
let reference = $reference.clone();
let weak_button = Arc::downgrade(&[<$item _button>]);
2025-03-05 08:45:39 +00:00
move |world, selected| {
2025-02-28 07:43:35 +00:00
if selected {
2025-03-05 08:45:39 +00:00
let entity = unsafe { remove_life_time(world.entity($hero)?) };
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let attributes = entity.get_component::<Attributes>()?;
let items = entity.get_component::<ItemSlotContainer>()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
match items.$item() {
Some($item) => {
let button_pos =
weak_button.upgrade().unwrap().position_extent();
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let gui = Self::create_tooltip(
world,
$item,
attributes,
button_pos,
)?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
reference.upgrade().unwrap().add_tooltip("equip", gui);
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
None => {
2025-03-06 16:30:50 +00:00
reference.upgrade().unwrap().remove_tooltip(world, "equip")?;
2025-03-05 08:45:39 +00:00
}
}
2025-02-28 07:43:35 +00:00
} else {
2025-03-06 16:30:50 +00:00
reference.upgrade().unwrap().remove_tooltip(world, "equip")?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
});
[<$item _button>].set_callback({
let reference = $reference.clone();
2025-03-05 08:45:39 +00:00
move |world| {
2025-02-28 07:43:35 +00:00
let mut found_item = false;
2025-03-05 08:45:39 +00:00
let (entity, resources) = world.entity_resources($hero)?;
2025-02-28 07:43:35 +00:00
2025-04-06 05:17:03 +00:00
let (
items,
inventory,
statistics,
attributes,
status
): (
&mut ItemSlotContainer,
&mut Inventory<A>,
&mut Statistics,
&mut Attributes,
&mut CharacterStatus
) = entity.get_components_mut()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
if let Some($item) = items.[<$item>]() {
inventory.add_item($item.clone());
found_item = true;
}
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
if found_item {
2025-04-06 05:17:03 +00:00
items.[<unset_ $item>](entity)?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
statistics.update(
attributes,
resources.get::<AttributeSettings>(),
(&*items, resources.get::<ItemSettings>())
);
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
if status.current_health > statistics.health {
status.current_health = statistics.health.clone();
2025-02-28 07:43:35 +00:00
}
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory::<A>();
2025-03-05 08:45:39 +00:00
inventory.update_page(world, true)?;
2025-02-28 07:43:35 +00:00
}
}
Ok(())
}
});
[<$item _button>].set_custom_callback({
let reference = $reference.clone();
2025-03-05 08:45:39 +00:00
move |world, controller_button| {
2025-02-28 07:43:35 +00:00
Ok(match controller_button {
ControllerButton::Y => {
let mut empty_affixes_found = false;
2025-03-05 08:45:39 +00:00
let entity = world.entity_mut($hero)?;
let items = entity.get_component::<ItemSlotContainer>()?;
if let Some(item) = items.$item().clone() {
if item.affixes.iter().any(|affix| {
if let ItemAffix::Socket(None) = affix {
true
} else {
false
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
}) {
let socket_object = world.resources.get_mut::<Option<ReferenceObject>>();
*socket_object = Some(ReferenceObject::Item {
item,
source: ReferenceItemSource::Slots(None),
});
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
empty_affixes_found = true;
}
}
2025-02-28 07:43:35 +00:00
if empty_affixes_found {
let window = reference.upgrade().unwrap();
let mut tabs = window.tabs_mut();
let inventory = tabs.inventory::<A>();
2025-03-05 08:45:39 +00:00
inventory.switch_to_jewels(world)?;
2025-02-28 07:43:35 +00:00
}
true
}
_ => false,
})
}
});
}
};
2025-03-05 08:45:39 +00:00
($self:ident, $reference:ident, $hero:ident, $item:ident, $button:literal, $index:literal) => {
2025-02-28 07:43:35 +00:00
paste::expr! {
let [<$item _button>]: Arc<Button> = $self.snippet.element($button)?;
[<$item _button>].set_select_callback({
let reference = $reference.clone();
let weak_button = Arc::downgrade(&[<$item _button>]);
2025-03-05 08:45:39 +00:00
move |world, selected| {
2025-02-28 07:43:35 +00:00
if selected {
2025-03-05 08:45:39 +00:00
let entity = unsafe { remove_life_time(world.entity($hero)?) };
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let attributes = entity.get_component::<Attributes>()?;
let items = entity.get_component::<ItemSlotContainer>()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
match items.$item($index) {
Some($item) => {
let button_pos =
weak_button.upgrade().unwrap().position_extent();
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let gui = Self::create_tooltip(
world,
$item,
attributes,
button_pos,
)?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
reference.upgrade().unwrap().add_tooltip("equip", gui);
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
None => {
2025-03-06 16:30:50 +00:00
reference.upgrade().unwrap().remove_tooltip(world, "equip")?;
2025-03-05 08:45:39 +00:00
}
}
2025-02-28 07:43:35 +00:00
} else {
2025-03-06 16:30:50 +00:00
reference.upgrade().unwrap().remove_tooltip(world, "equip")?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
});
[<$item _button>].set_callback({
let reference = $reference.clone();
2025-03-05 08:45:39 +00:00
move |world| {
2025-02-28 07:43:35 +00:00
let mut found_item = false;
2025-03-05 08:45:39 +00:00
let (entity, resources) = world.entity_resources($hero)?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let items = multi_mut.get::<ItemSlotContainer>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
if let Some($item) = items.[<$item>]($index) {
inventory.add_item($item.clone());
found_item = true;
}
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
if found_item {
items.[<unset_ $item>]($index)?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let statistics = multi_mut.get::<Statistics>()?;
let attributes = multi_mut.get::<Attributes>()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
statistics.update(
attributes,
resources.get::<AttributeSettings>(),
(&*items, resources.get::<ItemSettings>())
);
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let status = multi_mut.get::<CharacterStatus>()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
if status.current_health > statistics.health {
status.current_health = statistics.health.clone();
2025-02-28 07:43:35 +00:00
}
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory::<A>();
2025-03-05 08:45:39 +00:00
inventory.update_page(world, true)?;
2025-02-28 07:43:35 +00:00
}
}
Ok(())
}
});
[<$item _button>].set_custom_callback({
let reference = $reference.clone();
2025-03-05 08:45:39 +00:00
move |world, controller_button| {
2025-02-28 07:43:35 +00:00
Ok(match controller_button {
ControllerButton::Y => {
let mut empty_affixes_found = false;
2025-03-05 08:45:39 +00:00
let entity = world.entity_mut($hero)?;
let items = entity.get_component::<ItemSlotContainer>()?;
if let Some(item) = items.$item($index).clone() {
if item.affixes.iter().any(|affix| {
if let ItemAffix::Socket(None) = affix {
true
} else {
false
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
}) {
let socket_object = world.resources.get_mut::<Option<ReferenceObject>>();
*socket_object = Some(ReferenceObject::Item {
item,
source: ReferenceItemSource::Slots(Some($index)),
});
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
empty_affixes_found = true;
}
}
2025-02-28 07:43:35 +00:00
if empty_affixes_found {
let window = reference.upgrade().unwrap();
let mut tabs = window.tabs_mut();
let inventory = tabs.inventory::<A>();
2025-03-05 08:45:39 +00:00
inventory.switch_to_jewels(world)?;
2025-02-28 07:43:35 +00:00
}
true
}
_ => false,
})
}
});
}
};
}
#[macro_export]
macro_rules! equip_update {
2025-03-05 08:45:39 +00:00
($gui:ident, $gui_handler:ident, $items:ident, $part:ident, $icons:ident) => {{
2025-02-28 07:43:35 +00:00
let button: Arc<Button> = $gui.element(stringify!($part))?;
match $items.$part() {
2025-03-05 08:45:39 +00:00
Some($part) => button.set_icon($gui_handler, &$part.icon)?,
None => button.set_icon($gui_handler, &$icons.$part)?,
2025-02-28 07:43:35 +00:00
}
}};
2025-03-05 08:45:39 +00:00
($gui:ident, $gui_handler:ident, $items:ident, $part:ident, $icons:ident, $name:literal) => {{
2025-02-28 07:43:35 +00:00
let button: Arc<Button> = $gui.element($name)?;
match $items.$part() {
2025-03-05 08:45:39 +00:00
Some($part) => button.set_icon($gui_handler, &$part.icon)?,
None => button.set_icon($gui_handler, &$icons.$part)?,
2025-02-28 07:43:35 +00:00
}
}};
2025-03-05 08:45:39 +00:00
($gui:ident, $gui_handler:ident, $items:ident, $part:ident, $icons:ident, $name:literal, $index:literal) => {{
2025-02-28 07:43:35 +00:00
let button: Arc<Button> = $gui.element($name)?;
match $items.$part($index) {
2025-03-05 08:45:39 +00:00
Some($part) => button.set_icon($gui_handler, &$part.icon)?,
None => button.set_icon($gui_handler, &$icons.$part)?,
2025-02-28 07:43:35 +00:00
}
}};
}
}