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::{ content::{Content, ContentUpdate}, CharacterWindow, }; use super::jewel_right_side::{LowerJewels, ReferenceItemSource, ReferenceObject}; impl Content { fn salvage_item(engine: &Arc, hero: Entity, item_index: usize) -> Result<()> { CharacterWindow::salvage_from_inventory::(engine, 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(engine: &Arc, hero: Entity, item_index: usize) -> Result { let mut has_empty_sockets = true; engine.on_scene_mut(|scene| { let entity = scene.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 = scene.resources.get_mut::>(); *socket_object = Some(ReferenceObject::Item { item, source: ReferenceItemSource::Inventory(item_index), }); } else { has_empty_sockets = false; } Ok(()) })?; Ok(has_empty_sockets) } fn equip_item(engine: &Arc, hero: Entity, item_index: usize) -> Result<()> { engine.on_scene_mut(|scene| { let (resources, entity) = scene.entity_resource(hero)?; let mut multi_mut = entity.multi_mut(); let hero_items = multi_mut.get::()?; let inventory = multi_mut.get::>()?; let attributes = multi_mut.get::()?; // 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, &mut multi_mut)? { inventory.insert_item(old_item, item_index); } // update hero stats let statistics = multi_mut.get::()?; statistics.update( attributes, resources.get::(), (&*hero_items, resources.get::()), ); Ok(()) }) } fn show_item_tooltip( engine: &Arc, hero: Entity, item_index: usize, reference: &Weak, (x, y, w, _h): (i32, i32, u32, u32), ) -> Result<()> { engine.on_scene(|scene| { let entity = scene.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(engine.gui_handler(), attributes, (target_x, target_y))?; gui.enable()?; 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( engine.gui_handler(), attributes, (start_x, start_y), )?; compare_gui.enable()?; gui.perform_double_check(&compare_gui, x, spacing as u32)?; window.add_tooltip("equip", compare_gui); } None => { gui.perform_single_check(x, y)?; } } window.add_tooltip(format!("item_{item_index}"), gui); Ok(()) })?; Ok(()) } } impl ContentUpdate for Content { fn update(&mut self, engine: &Arc, hero: Entity) -> Result<()> { let reference = self.reference.clone(); self.update_base(engine, |button, t, index| { button.set_icon(&t.icon)?; button.set_custom_callback({ let reference = reference.clone(); let engine = engine.clone(); move |controller_button| { Ok(match controller_button { ControllerButton::X => { Self::salvage_item(&engine, hero, index)?; if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.update_page(true)?; } true } ControllerButton::Y => { if Self::select_to_socket(&engine, hero, index)? { if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.switch_to_jewels()?; } } true } _ => false, }) } }); button.set_callback({ let reference = reference.clone(); let engine = engine.clone(); move || { Self::equip_item(&engine, hero, index)?; if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.update_page(true)?; } Ok(()) } }); button.set_select_callback({ let weak_button = Arc::downgrade(&button); let reference = reference.clone(); let engine = engine.clone(); move |selected| { if selected { let button_pos = weak_button.upgrade().unwrap().position_extent(); Self::show_item_tooltip(&engine, hero, index, &reference, button_pos)?; } else { let window = reference.upgrade().unwrap(); window.remove_tooltip(format!("item_{index}")); window.remove_tooltip("equip"); } Ok(()) } }); Ok(()) }) } fn select(&self) -> Result<()> { self.select() } } impl Content { fn show_jewel_tooltip( engine: &Arc, hero: Entity, item_index: usize, reference: &Weak, (x, y, w, _h): (i32, i32, u32, u32), ) -> Result<()> { engine.on_scene(|scene| { let entity = scene.entity(hero)?; let inventory = entity.get_component::>()?; let target_x = x + w as i32; let target_y = y; let jewel = inventory.jewel_at(item_index); let gui = jewel.create_tooltip( engine.gui_handler(), scene.resources.get::(), (target_x, target_y), )?; gui.enable()?; gui.perform_single_check(x, y)?; reference .upgrade() .unwrap() .add_tooltip(format!("jewel_{item_index}"), gui); Ok(()) })?; Ok(()) } fn select_to_combine(engine: &Arc, hero: Entity, jewel_index: usize) -> Result<()> { engine.on_scene_mut(|scene| { let entity = scene.entity(hero)?; let inventory = entity.get_component::>()?; let jewel = inventory.jewel_at(jewel_index).clone(); // add to reference let socket_object = scene.resources.get_mut::>(); *socket_object = Some(ReferenceObject::Jewel { jewel, index: jewel_index, }); // remove from lower if placed there let lower_jewels = scene.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(engine: &Arc, hero: Entity, jewel_index: usize) -> Result<()> { engine.on_scene_mut(|scene| { let entity = scene.entity(hero)?; let inventory = entity.get_component::>()?; let jewel = inventory.jewel_at(jewel_index).clone(); // remove from reference if placed there let socket_object = scene.resources.get_mut::>(); if let Some(ReferenceObject::Jewel { index, .. }) = socket_object { if *index == jewel_index { *socket_object = None; } } let lower_jewels = scene.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, engine: &Arc, hero: Entity) -> Result<()> { let reference = self.reference.clone(); self.update_base(engine, |button, t, index| { button.set_icon(&t.icon())?; button.set_select_callback({ let weak_button = Arc::downgrade(&button); let engine = engine.clone(); let reference = reference.clone(); move |selected| { if selected { let button_pos = weak_button.upgrade().unwrap().position_extent(); Self::show_jewel_tooltip(&engine, hero, index, &reference, button_pos)?; } else { let window = reference.upgrade().unwrap(); window.remove_tooltip(format!("jewel_{index}")); } Ok(()) } }); button.set_callback({ let engine = engine.clone(); let reference = reference.clone(); move || { Self::select_to_lower(&engine, hero, index)?; if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.update_page(true)?; } Ok(()) } }); button.set_custom_callback({ let engine = engine.clone(); let reference = reference.clone(); move |controller_button| { Ok(match controller_button { ControllerButton::Y => { Self::select_to_combine(&engine, hero, index)?; if let Some(menu) = reference.upgrade() { let mut tabs = menu.tabs_mut(); let inventory = tabs.inventory::(); inventory.update_page(true)?; } true } _ => false, }) } }); Ok(()) }) } fn select(&self) -> Result<()> { self.select() } } impl ContentUpdate for Content { fn update(&mut self, engine: &Arc, _hero: Entity) -> Result<()> { self.update_base(engine, |_button, _t, _index| { // button.set_icon(&t.icon)?; Ok(()) }) } fn select(&self) -> Result<()> { self.select() } }