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, content::{Content, ContentUpdate}, }; use super::jewel_right_side::{LowerJewels, ReferenceItemSource, ReferenceObject}; impl Content { fn salvage_item(world: &mut World, hero: Entity, item_index: usize) -> Result<()> { CharacterWindow::salvage_from_inventory::(world, hero, |inventory| { 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 }) } fn select_to_socket(world: &mut World, hero: Entity, item_index: usize) -> Result { let mut has_empty_sockets = true; let entity = world.entity(hero)?; let inventory = entity.get_component::>()?; let item = inventory.item_at(item_index).clone(); if item.affixes.iter().any(|affix| { if let ItemAffix::Socket(None) = affix { true } else { false } }) { let socket_object: &mut ReferenceObject = world.resources.get_mut()?; *socket_object = ReferenceObject::Item { item, source: ReferenceItemSource::Inventory(item_index), }; } else { has_empty_sockets = false; } Ok(has_empty_sockets) } fn equip_item(world: &mut World, hero: Entity, item_index: usize) -> Result<()> { let (entity, resources) = world.entity_resources(hero)?; let (hero_items, inventory, attributes, statistics): ( &mut ItemSlotContainer, &mut Inventory, &mut Attributes, &mut Statistics, ) = entity.get_components_mut()?; // remove item from inventory let item = inventory.remove_item(item_index); // add or swap items with equipment if let Some(old_item) = hero_items.insert(item.clone(), attributes)? { inventory.insert_item(old_item, item_index); } // update hero stats statistics.update( attributes, resources.get::(), (&*hero_items, resources.get::()), ); Ok(()) } fn show_item_tooltip( world: &mut World, hero: Entity, item_index: usize, reference: &Weak, (x, y, w, _h): (i32, i32, u32, u32), ) -> Result<()> { let entity = unsafe { remove_life_time(world.entity(hero)?) }; let inventory = entity.get_component::>()?; let attributes = entity.get_component::()?; let target_x = x + w as i32; let target_y = y; let item = inventory.item_at(item_index); let gui = item.create_tooltip(world, attributes, (target_x, target_y))?; gui.enable(world)?; let window = reference.upgrade().unwrap(); let items = entity.get_component::()?; match items.item_at(item.slot) { Some(equipped) => { let grid_pos = gui.position_extent(); let spacing = 2; let start_x = grid_pos.0 + grid_pos.2 as i32 + spacing; let start_y = grid_pos.1; let compare_gui = equipped.create_tooltip(world, attributes, (start_x, start_y))?; compare_gui.enable(world)?; gui.perform_double_check( &compare_gui, world.resources.get_mut()?, x, spacing as u32, )?; window.add_tooltip("equip", compare_gui); } None => { gui.perform_single_check(world.resources.get_mut()?, x, y)?; } } window.add_tooltip(format!("item_{item_index}"), gui); Ok(()) } } impl ContentUpdate for Content { fn update(&mut self, world: &mut World, hero: Entity) -> Result<()> { let reference = self.reference.clone(); self.update_base(world, |world, button, t, index| { button.set_icon(world.resources.get_mut()?, &t.icon)?; button.set_custom_callback({ let reference = reference.clone(); move |world, controller_button| { Ok(match controller_button { ControllerButton::X => { Self::salvage_item(world, hero, index)?; if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.update_page(world, true)?; } true } ControllerButton::Y => { if Self::select_to_socket(world, hero, index)? { if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.switch_to_jewels(world)?; } } true } _ => false, }) } }); button.set_callback({ let reference = reference.clone(); move |world| { Self::equip_item(world, hero, index)?; if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.update_page(world, true)?; } Ok(()) } }); button.set_select_callback({ let weak_button = Arc::downgrade(&button); let reference = reference.clone(); move |world, selected| { if selected { let button_pos = weak_button.upgrade().unwrap().position_extent(); Self::show_item_tooltip(world, hero, index, &reference, button_pos)?; } else { let window = reference.upgrade().unwrap(); window.remove_tooltip(world, format!("item_{index}"))?; window.remove_tooltip(world, "equip")?; } Ok(()) } }); Ok(()) }) } fn select(&self, world: &mut World) -> Result<()> { self.select(world.resources.get_mut()?) } } impl Content { fn show_jewel_tooltip( world: &mut World, hero: Entity, item_index: usize, reference: &Weak, (x, y, w, _h): (i32, i32, u32, u32), ) -> Result<()> { let entity = unsafe { remove_life_time(world.entity(hero)?) }; let inventory = entity.get_component::>()?; let target_x = x + w as i32; let target_y = y; let item_settings = world.resources.get_unchecked::(); let jewel = inventory.jewel_at(item_index); let gui = jewel.create_tooltip(world, item_settings, (target_x, target_y))?; gui.enable(world)?; gui.perform_single_check(world.resources.get_mut()?, x, y)?; reference .upgrade() .unwrap() .add_tooltip(format!("jewel_{item_index}"), gui); Ok(()) } fn select_to_combine(world: &mut World, hero: Entity, jewel_index: usize) -> Result<()> { let entity = world.entity(hero)?; let inventory = entity.get_component::>()?; let jewel = inventory.jewel_at(jewel_index).clone(); // add to reference let socket_object: &mut ReferenceObject = world.resources.get_mut()?; *socket_object = ReferenceObject::Jewel { jewel, index: jewel_index, }; // remove from lower if placed there let lower_jewels: &mut LowerJewels = world.resources.get_mut()?; 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(()) } fn select_to_lower(world: &mut World, hero: Entity, jewel_index: usize) -> Result<()> { let entity = world.entity(hero)?; let inventory = entity.get_component::>()?; let jewel = inventory.jewel_at(jewel_index).clone(); // remove from reference if placed there let socket_object: &mut ReferenceObject = world.resources.get_mut()?; if let Some(ReferenceObject::Jewel { index, .. }) = socket_object.some() { if *index == jewel_index { *socket_object = ReferenceObject::Empty; } } let lower_jewels: &mut LowerJewels = world.resources.get_mut()?; // 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)), } } Ok(()) } } impl ContentUpdate for Content { fn update(&mut self, world: &mut World, hero: Entity) -> Result<()> { let reference = self.reference.clone(); self.update_base(world, |world, button, t, index| { button.set_icon(world.resources.get_mut()?, &t.icon())?; button.set_select_callback({ let weak_button = Arc::downgrade(&button); let reference = reference.clone(); move |world, selected| { if selected { let button_pos = weak_button.upgrade().unwrap().position_extent(); Self::show_jewel_tooltip(world, hero, index, &reference, button_pos)?; } else { let window = reference.upgrade().unwrap(); window.remove_tooltip(world, format!("jewel_{index}"))?; } Ok(()) } }); button.set_callback({ let reference = reference.clone(); move |world| { Self::select_to_lower(world, hero, index)?; if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.update_page(world, true)?; } Ok(()) } }); button.set_custom_callback({ let reference = reference.clone(); move |world, controller_button| { Ok(match controller_button { ControllerButton::Y => { Self::select_to_combine(world, hero, index)?; if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.update_page(world, true)?; } true } _ => false, }) } }); Ok(()) }) } fn select(&self, world: &mut World) -> Result<()> { self.select(world.resources.get_mut()?) } } impl ContentUpdate for Content { fn update(&mut self, world: &mut World, _hero: Entity) -> Result<()> { self.update_base(world, |_world, _button, _t, _index| { // button.set_icon(&t.icon)?; Ok(()) }) } fn select(&self, world: &mut World) -> Result<()> { self.select(world.resources.get_mut()?) } }