rpg_base/character_window/src/inventory/content.rs

408 lines
13 KiB
Rust
Raw Normal View History

2025-02-28 07:43:35 +00:00
use std::sync::{Arc, Weak};
use rpg_components::components::attributes::Attributes;
use rpg_components::components::inventory::{Inventory, Storable};
use rpg_components::components::item_slots::ItemSlotContainer;
use rpg_components::components::statistics::Statistics;
use rpg_components::config::attributes::AttributeSettings;
use rpg_components::config::items::ItemSettings;
use rpg_components::items::{Item, ItemAffix, Jewel, MapItem};
use crate::*;
use crate::{
CharacterWindow,
2025-03-05 08:45:39 +00:00
content::{Content, ContentUpdate},
2025-02-28 07:43:35 +00:00
};
use super::jewel_right_side::{LowerJewels, ReferenceItemSource, ReferenceObject};
impl<A: Ability + 'static> Content<A, Item> {
2025-03-05 08:45:39 +00:00
fn salvage_item(world: &mut World, hero: Entity, item_index: usize) -> Result<()> {
CharacterWindow::salvage_from_inventory::<A, _, _>(world, hero, |inventory| {
2025-02-28 07:43:35 +00:00
let mut item = inventory.remove_item(item_index);
// unsocket jewels and add them into inventory
item.affixes
.iter_mut()
.filter_map(|affix| match affix {
ItemAffix::Socket(j) => j.take(),
ItemAffix::Stat(_) => None,
})
.for_each(|jewel| {
inventory.add_jewel(jewel);
});
item
})
}
2025-03-05 08:45:39 +00:00
fn select_to_socket(world: &mut World, hero: Entity, item_index: usize) -> Result<bool> {
2025-02-28 07:43:35 +00:00
let mut has_empty_sockets = true;
2025-03-05 08:45:39 +00:00
let entity = world.entity(hero)?;
let inventory = entity.get_component::<Inventory<A>>()?;
let item = inventory.item_at(item_index).clone();
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
if item.affixes.iter().any(|affix| {
if let ItemAffix::Socket(None) = affix {
true
2025-02-28 07:43:35 +00:00
} else {
2025-03-05 08:45:39 +00:00
false
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
}) {
2025-04-05 11:45:08 +00:00
let socket_object: &mut ReferenceObject = world.resources.get_mut()?;
2025-02-28 07:43:35 +00:00
2025-04-05 11:45:08 +00:00
*socket_object = ReferenceObject::Item {
2025-03-05 08:45:39 +00:00
item,
source: ReferenceItemSource::Inventory(item_index),
2025-04-05 11:45:08 +00:00
};
2025-03-05 08:45:39 +00:00
} else {
has_empty_sockets = false;
}
2025-02-28 07:43:35 +00:00
Ok(has_empty_sockets)
}
2025-03-05 08:45:39 +00:00
fn equip_item(world: &mut World, hero: Entity, item_index: usize) -> Result<()> {
let (entity, resources) = world.entity_resources(hero)?;
2025-02-28 07:43:35 +00:00
2025-04-05 12:18:41 +00:00
let (hero_items, inventory, attributes, statistics): (
&mut ItemSlotContainer,
&mut Inventory<A>,
&mut Attributes,
&mut Statistics,
) = entity.get_components_mut()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
// remove item from inventory
let item = inventory.remove_item(item_index);
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
// add or swap items with equipment
2025-04-06 07:23:11 +00:00
if let Some(old_item) = hero_items.insert(item.clone(), attributes)? {
2025-03-05 08:45:39 +00:00
inventory.insert_item(old_item, item_index);
}
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
// update hero stats
statistics.update(
attributes,
resources.get::<AttributeSettings>(),
(&*hero_items, resources.get::<ItemSettings>()),
);
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
Ok(())
2025-02-28 07:43:35 +00:00
}
fn show_item_tooltip(
2025-03-05 08:45:39 +00:00
world: &mut World,
2025-02-28 07:43:35 +00:00
hero: Entity,
item_index: usize,
reference: &Weak<CharacterWindow>,
(x, y, w, _h): (i32, i32, u32, u32),
) -> Result<()> {
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 inventory = entity.get_component::<Inventory<A>>()?;
let attributes = entity.get_component::<Attributes>()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let target_x = x + w as i32;
let target_y = y;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let item = inventory.item_at(item_index);
let gui = item.create_tooltip(world, attributes, (target_x, target_y))?;
gui.enable(world)?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let window = reference.upgrade().unwrap();
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_at(item.slot) {
Some(equipped) => {
let grid_pos = gui.position_extent();
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let spacing = 2;
let start_x = grid_pos.0 + grid_pos.2 as i32 + spacing;
let start_y = grid_pos.1;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
let compare_gui = equipped.create_tooltip(world, attributes, (start_x, start_y))?;
compare_gui.enable(world)?;
gui.perform_double_check(
&compare_gui,
2025-04-05 11:45:08 +00:00
world.resources.get_mut()?,
2025-03-05 08:45:39 +00:00
x,
spacing as u32,
)?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
window.add_tooltip("equip", compare_gui);
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
None => {
2025-04-05 11:45:08 +00:00
gui.perform_single_check(world.resources.get_mut()?, x, y)?;
2025-03-05 08:45:39 +00:00
}
}
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
window.add_tooltip(format!("item_{item_index}"), gui);
2025-02-28 07:43:35 +00:00
Ok(())
}
}
impl<A: Ability + 'static> ContentUpdate for Content<A, Item> {
2025-03-05 08:45:39 +00:00
fn update(&mut self, world: &mut World, hero: Entity) -> Result<()> {
2025-02-28 07:43:35 +00:00
let reference = self.reference.clone();
2025-03-05 08:45:39 +00:00
self.update_base(world, |world, button, t, index| {
2025-04-05 11:45:08 +00:00
button.set_icon(world.resources.get_mut()?, &t.icon)?;
2025-02-28 07:43:35 +00:00
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::X => {
2025-03-05 08:45:39 +00:00
Self::salvage_item(world, hero, index)?;
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
}
true
}
ControllerButton::Y => {
2025-03-05 08:45:39 +00:00
if Self::select_to_socket(world, hero, index)? {
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.switch_to_jewels(world)?;
2025-02-28 07:43:35 +00:00
}
}
true
}
_ => false,
})
}
});
button.set_callback({
let reference = reference.clone();
2025-03-05 08:45:39 +00:00
move |world| {
Self::equip_item(world, hero, index)?;
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(())
}
});
button.set_select_callback({
let weak_button = Arc::downgrade(&button);
let reference = reference.clone();
2025-03-05 08:45:39 +00:00
move |world, selected| {
2025-02-28 07:43:35 +00:00
if selected {
let button_pos = weak_button.upgrade().unwrap().position_extent();
2025-03-05 08:45:39 +00:00
Self::show_item_tooltip(world, hero, index, &reference, button_pos)?;
2025-02-28 07:43:35 +00:00
} else {
let window = reference.upgrade().unwrap();
2025-03-06 16:30:50 +00:00
window.remove_tooltip(world, format!("item_{index}"))?;
window.remove_tooltip(world, "equip")?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
});
Ok(())
})
}
2025-03-05 08:45:39 +00:00
fn select(&self, world: &mut World) -> Result<()> {
2025-04-05 11:45:08 +00:00
self.select(world.resources.get_mut()?)
2025-02-28 07:43:35 +00:00
}
}
impl<A: Ability + 'static> Content<A, Jewel> {
fn show_jewel_tooltip(
2025-03-05 08:45:39 +00:00
world: &mut World,
2025-02-28 07:43:35 +00:00
hero: Entity,
item_index: usize,
reference: &Weak<CharacterWindow>,
(x, y, w, _h): (i32, i32, u32, u32),
) -> Result<()> {
2025-03-05 09:31:16 +00:00
let entity = unsafe { remove_life_time(world.entity(hero)?) };
2025-03-05 08:45:39 +00:00
let inventory = entity.get_component::<Inventory<A>>()?;
let target_x = x + w as i32;
let target_y = y;
2025-03-05 09:31:16 +00:00
let item_settings = world.resources.get_unchecked::<ItemSettings>();
2025-03-05 08:45:39 +00:00
let jewel = inventory.jewel_at(item_index);
2025-03-05 09:31:16 +00:00
let gui = jewel.create_tooltip(world, item_settings, (target_x, target_y))?;
2025-03-05 08:45:39 +00:00
gui.enable(world)?;
2025-04-05 11:45:08 +00:00
gui.perform_single_check(world.resources.get_mut()?, x, y)?;
2025-03-05 08:45:39 +00:00
reference
.upgrade()
.unwrap()
.add_tooltip(format!("jewel_{item_index}"), gui);
2025-02-28 07:43:35 +00:00
Ok(())
}
2025-03-05 08:45:39 +00:00
fn select_to_combine(world: &mut World, hero: Entity, jewel_index: usize) -> Result<()> {
let entity = world.entity(hero)?;
let inventory = entity.get_component::<Inventory<A>>()?;
let jewel = inventory.jewel_at(jewel_index).clone();
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
// add to reference
2025-04-05 11:45:08 +00:00
let socket_object: &mut ReferenceObject = world.resources.get_mut()?;
*socket_object = ReferenceObject::Jewel {
2025-03-05 08:45:39 +00:00
jewel,
index: jewel_index,
2025-04-05 11:45:08 +00:00
};
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
// remove from lower if placed there
2025-04-05 11:45:08 +00:00
let lower_jewels: &mut LowerJewels = world.resources.get_mut()?;
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
if let Some(position) = lower_jewels.jewels.iter().position(|jewel| match jewel {
Some((_, index)) => *index == jewel_index,
None => false,
}) {
lower_jewels.jewels[position] = None;
}
Ok(())
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
fn select_to_lower(world: &mut World, hero: Entity, jewel_index: usize) -> Result<()> {
let entity = world.entity(hero)?;
let inventory = entity.get_component::<Inventory<A>>()?;
let jewel = inventory.jewel_at(jewel_index).clone();
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
// remove from reference if placed there
2025-04-06 05:17:03 +00:00
let socket_object: &mut ReferenceObject = world.resources.get_mut()?;
if let Some(ReferenceObject::Jewel { index, .. }) = socket_object.some() {
2025-03-05 08:45:39 +00:00
if *index == jewel_index {
2025-04-06 05:17:03 +00:00
*socket_object = ReferenceObject::Empty;
2025-03-05 08:45:39 +00:00
}
}
2025-04-06 05:17:03 +00:00
let lower_jewels: &mut LowerJewels = world.resources.get_mut()?;
2025-03-05 08:45:39 +00:00
// check if that jewel is already added
if !lower_jewels.jewels.iter().any(|content| match content {
Some((_, index)) => *index == jewel_index,
None => false,
}) {
// search for an empty position in lower jewels
match lower_jewels.jewels.iter().position(|jewel| jewel.is_none()) {
Some(position) => lower_jewels.jewels[position] = Some((jewel, jewel_index)),
None => lower_jewels.jewels[0] = Some((jewel, jewel_index)),
2025-02-28 07:43:35 +00:00
}
2025-03-05 08:45:39 +00:00
}
2025-02-28 07:43:35 +00:00
2025-03-05 08:45:39 +00:00
Ok(())
2025-02-28 07:43:35 +00:00
}
}
impl<A: Ability + 'static> ContentUpdate for Content<A, Jewel> {
2025-03-05 08:45:39 +00:00
fn update(&mut self, world: &mut World, hero: Entity) -> Result<()> {
2025-02-28 07:43:35 +00:00
let reference = self.reference.clone();
2025-03-05 08:45:39 +00:00
self.update_base(world, |world, button, t, index| {
2025-04-05 11:45:08 +00:00
button.set_icon(world.resources.get_mut()?, &t.icon())?;
2025-02-28 07:43:35 +00:00
button.set_select_callback({
let weak_button = Arc::downgrade(&button);
let reference = reference.clone();
2025-03-05 08:45:39 +00:00
move |world, selected| {
2025-02-28 07:43:35 +00:00
if selected {
let button_pos = weak_button.upgrade().unwrap().position_extent();
2025-03-05 08:45:39 +00:00
Self::show_jewel_tooltip(world, hero, index, &reference, button_pos)?;
2025-02-28 07:43:35 +00:00
} else {
let window = reference.upgrade().unwrap();
2025-03-06 16:30:50 +00:00
window.remove_tooltip(world, format!("jewel_{index}"))?;
2025-02-28 07:43:35 +00:00
}
Ok(())
}
});
button.set_callback({
let reference = reference.clone();
2025-03-05 08:45:39 +00:00
move |world| {
Self::select_to_lower(world, hero, index)?;
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(())
}
});
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 => {
2025-03-05 08:45:39 +00:00
Self::select_to_combine(world, hero, index)?;
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
}
true
}
_ => false,
})
}
});
Ok(())
})
}
2025-03-05 08:45:39 +00:00
fn select(&self, world: &mut World) -> Result<()> {
2025-04-05 10:16:34 +00:00
self.select(world.resources.get_mut()?)
2025-02-28 07:43:35 +00:00
}
}
impl<A: Ability + 'static> ContentUpdate for Content<A, MapItem> {
2025-03-05 08:45:39 +00:00
fn update(&mut self, world: &mut World, _hero: Entity) -> Result<()> {
self.update_base(world, |_world, _button, _t, _index| {
2025-02-28 07:43:35 +00:00
// button.set_icon(&t.icon)?;
Ok(())
})
}
2025-03-05 08:45:39 +00:00
fn select(&self, world: &mut World) -> Result<()> {
2025-04-05 10:16:34 +00:00
self.select(world.resources.get_mut()?)
2025-02-28 07:43:35 +00:00
}
}