rpg_base/character_window/src/inventory/item_right_side.rs

532 lines
21 KiB
Rust
Raw Normal View History

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>(
engine: &Arc<Engine>,
file: &str,
reference: &Weak<CharacterWindow>,
hero: Entity,
) -> Result<Self> {
let snippet = GuiSnippet::from_str(engine.gui_handler(), file)?;
let icons = InventoryEmptyIcons::new(engine)?;
let me = Self {
snippet,
empty_icons: icons,
};
me.setup::<A>(engine, reference, hero)?;
Ok(me)
}
fn setup<A: Ability + 'static>(
&self,
engine: &Arc<Engine>,
reference: &Weak<CharacterWindow>,
hero: Entity,
) -> Result<()> {
button_setup!(self, engine, reference, hero, helmet, "helmet");
button_setup!(self, engine, reference, hero, chest, "chest");
button_setup!(self, engine, reference, hero, gloves, "gloves");
button_setup!(self, engine, reference, hero, belt, "belt");
button_setup!(self, engine, reference, hero, boots, "boots");
#[rustfmt::skip]
button_setup!(self, engine, reference, hero, primary_hand, "main hand");
#[rustfmt::skip]
button_setup!(self, engine, reference, hero, secondary_hand, "off hand");
#[rustfmt::skip]
button_setup!(self, engine, reference, hero, amulet, "amulet_0", 0);
#[rustfmt::skip]
button_setup!(self, engine, reference, hero, amulet, "amulet_1", 1);
#[rustfmt::skip]
button_setup!(self, engine, reference, hero, ring, "ring_0", 0);
#[rustfmt::skip]
button_setup!(self, engine, reference, hero, ring, "ring_1", 1);
#[rustfmt::skip]
button_setup!(self, engine, reference, hero, ring, "ring_2", 2);
#[rustfmt::skip]
button_setup!(self, engine, reference, hero, ring, "ring_3", 3);
Ok(())
}
fn update_icons(&self, items: &ItemSlotContainer) -> Result<()> {
let ui = &self.snippet;
let empty_icons = &self.empty_icons;
equip_update!(ui, items, helmet, empty_icons);
equip_update!(ui, items, chest, empty_icons);
equip_update!(ui, items, boots, empty_icons);
equip_update!(ui, items, gloves, empty_icons);
equip_update!(ui, items, belt, empty_icons);
equip_update!(ui, items, primary_hand, empty_icons, "main hand");
equip_update!(ui, items, secondary_hand, empty_icons, "off hand");
equip_update!(ui, items, ring, empty_icons, "ring_0", 0);
equip_update!(ui, items, ring, empty_icons, "ring_1", 1);
equip_update!(ui, items, ring, empty_icons, "ring_2", 2);
equip_update!(ui, items, ring, empty_icons, "ring_3", 3);
equip_update!(ui, items, amulet, empty_icons, "amulet_0", 0);
equip_update!(ui, items, amulet, empty_icons, "amulet_1", 1);
Ok(())
}
fn create_tooltip(
engine: &Arc<Engine>,
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;
let gui = item.create_tooltip(engine.gui_handler(), attributes, (target_x, target_y))?;
gui.enable()?;
gui.perform_single_check(x, y)?;
Ok(gui)
}
}
impl RightSide for ItemRightSide {
fn refresh(&mut self, engine: &Engine, hero: Entity) -> Result<()> {
engine.on_scene(|scene| {
let hero_object = scene.entity(hero)?;
let items = hero_object.get_component::<ItemSlotContainer>()?;
self.update_icons(items)?;
Ok(())
})?;
Ok(())
}
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 {
fn new(engine: &Engine) -> Result<Self> {
let place_holder_settings = &engine
.scene()
.resources
.get::<ItemSettings>()
.icon_place_holder_paths;
Ok(Self {
helmet: Image::from_file(place_holder_settings.helmet.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
chest: Image::from_file(place_holder_settings.chest.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
belt: Image::from_file(place_holder_settings.belt.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
boots: Image::from_file(place_holder_settings.boots.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
gloves: Image::from_file(place_holder_settings.gloves.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
primary_hand: Image::from_file(place_holder_settings.main_hand.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
secondary_hand: Image::from_file(place_holder_settings.off_hand.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
ring: Image::from_file(place_holder_settings.ring.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
amulet: Image::from_file(place_holder_settings.amulet.clone())?
.attach_sampler(Sampler::pretty_sampler().build(engine.device())?)
.build(engine.device(), engine.queue())?,
})
}
}
mod macros {
#[macro_export]
macro_rules! button_setup {
($self:ident, $engine:ident, $reference:ident, $hero:ident, $item:ident, $button:literal) => {
paste::expr! {
let [<$item _button>]: Arc<Button> = $self.snippet.element($button)?;
[<$item _button>].set_select_callback({
let engine = $engine.clone();
let reference = $reference.clone();
let weak_button = Arc::downgrade(&[<$item _button>]);
move |selected| {
if selected {
engine.on_scene(|scene| {
let entity = scene.entity($hero)?;
let attributes = entity.get_component::<Attributes>()?;
let items = entity.get_component::<ItemSlotContainer>()?;
match items.$item() {
Some($item) => {
let button_pos =
weak_button.upgrade().unwrap().position_extent();
let gui = Self::create_tooltip(
&engine,
$item,
attributes,
button_pos,
)?;
reference.upgrade().unwrap().add_tooltip("equip", gui);
}
None => {
reference.upgrade().unwrap().remove_tooltip("equip");
}
}
Ok(())
})?;
} else {
reference.upgrade().unwrap().remove_tooltip("equip");
}
Ok(())
}
});
[<$item _button>].set_callback({
let engine = $engine.clone();
let reference = $reference.clone();
move || {
let mut found_item = false;
engine.on_scene_mut(|scene| {
let (resources, entity) = scene.entity_resource($hero)?;
let mut multi_mut = entity.multi_mut();
let items = multi_mut.get::<ItemSlotContainer>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
if let Some($item) = items.[<$item>]() {
inventory.add_item($item.clone());
found_item = true;
}
if found_item {
items.[<unset_ $item>](&mut multi_mut)?;
let statistics = multi_mut.get::<Statistics>()?;
let attributes = multi_mut.get::<Attributes>()?;
statistics.update(
attributes,
resources.get::<AttributeSettings>(),
(&*items, resources.get::<ItemSettings>())
);
let status = multi_mut.get::<CharacterStatus>()?;
if status.current_health > statistics.health {
status.current_health = statistics.health.clone();
}
}
Ok(())
})?;
if found_item {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
}
Ok(())
}
});
[<$item _button>].set_custom_callback({
let engine = $engine.clone();
let reference = $reference.clone();
move |controller_button| {
Ok(match controller_button {
ControllerButton::Y => {
let mut empty_affixes_found = false;
engine.on_scene_mut(|scene| {
let entity = scene.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
}
}) {
let socket_object = scene.resources.get_mut::<Option<ReferenceObject>>();
*socket_object = Some(ReferenceObject::Item {
item,
source: ReferenceItemSource::Slots(None),
});
empty_affixes_found = true;
}
}
Ok(())
})?;
if empty_affixes_found {
let window = reference.upgrade().unwrap();
let mut tabs = window.tabs_mut();
let inventory = tabs.inventory::<A>();
inventory.switch_to_jewels()?;
}
true
}
_ => false,
})
}
});
}
};
($self:ident, $engine:ident, $reference:ident, $hero:ident, $item:ident, $button:literal, $index:literal) => {
paste::expr! {
let [<$item _button>]: Arc<Button> = $self.snippet.element($button)?;
[<$item _button>].set_select_callback({
let engine = $engine.clone();
let reference = $reference.clone();
let weak_button = Arc::downgrade(&[<$item _button>]);
move |selected| {
if selected {
engine.on_scene(|scene| {
let entity = scene.entity($hero)?;
let attributes = entity.get_component::<Attributes>()?;
let items = entity.get_component::<ItemSlotContainer>()?;
match items.$item($index) {
Some($item) => {
let button_pos =
weak_button.upgrade().unwrap().position_extent();
let gui = Self::create_tooltip(
&engine,
$item,
attributes,
button_pos,
)?;
reference.upgrade().unwrap().add_tooltip("equip", gui);
}
None => {
reference.upgrade().unwrap().remove_tooltip("equip");
}
}
Ok(())
})?;
} else {
reference.upgrade().unwrap().remove_tooltip("equip");
}
Ok(())
}
});
[<$item _button>].set_callback({
let engine = $engine.clone();
let reference = $reference.clone();
move || {
let mut found_item = false;
engine.on_scene_mut(|scene| {
let (resources, entity) = scene.entity_resource($hero)?;
let mut multi_mut = entity.multi_mut();
let items = multi_mut.get::<ItemSlotContainer>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
if let Some($item) = items.[<$item>]($index) {
inventory.add_item($item.clone());
found_item = true;
}
if found_item {
items.[<unset_ $item>]($index)?;
let statistics = multi_mut.get::<Statistics>()?;
let attributes = multi_mut.get::<Attributes>()?;
statistics.update(
attributes,
resources.get::<AttributeSettings>(),
(&*items, resources.get::<ItemSettings>())
);
let status = multi_mut.get::<CharacterStatus>()?;
if status.current_health > statistics.health {
status.current_health = statistics.health.clone();
}
}
Ok(())
})?;
if found_item {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
}
Ok(())
}
});
[<$item _button>].set_custom_callback({
let engine = $engine.clone();
let reference = $reference.clone();
move |controller_button| {
Ok(match controller_button {
ControllerButton::Y => {
let mut empty_affixes_found = false;
engine.on_scene_mut(|scene| {
let entity = scene.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
}
}) {
let socket_object = scene.resources.get_mut::<Option<ReferenceObject>>();
*socket_object = Some(ReferenceObject::Item {
item,
source: ReferenceItemSource::Slots(Some($index)),
});
empty_affixes_found = true;
}
}
Ok(())
})?;
if empty_affixes_found {
let window = reference.upgrade().unwrap();
let mut tabs = window.tabs_mut();
let inventory = tabs.inventory::<A>();
inventory.switch_to_jewels()?;
}
true
}
_ => false,
})
}
});
}
};
}
#[macro_export]
macro_rules! equip_update {
($gui:ident, $items:ident, $part:ident, $icons:ident) => {{
let button: Arc<Button> = $gui.element(stringify!($part))?;
match $items.$part() {
Some($part) => button.set_icon(&$part.icon)?,
None => button.set_icon(&$icons.$part)?,
}
}};
($gui:ident, $items:ident, $part:ident, $icons:ident, $name:literal) => {{
let button: Arc<Button> = $gui.element($name)?;
match $items.$part() {
Some($part) => button.set_icon(&$part.icon)?,
None => button.set_icon(&$icons.$part)?,
}
}};
($gui:ident, $items:ident, $part:ident, $icons:ident, $name:literal, $index:literal) => {{
let button: Arc<Button> = $gui.element($name)?;
match $items.$part($index) {
Some($part) => button.set_icon(&$part.icon)?,
None => button.set_icon(&$icons.$part)?,
}
}};
}
}