407 lines
13 KiB
Rust
407 lines
13 KiB
Rust
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<A: Ability + 'static> Content<A, Item> {
|
|
fn salvage_item(world: &mut World, hero: Entity, item_index: usize) -> Result<()> {
|
|
CharacterWindow::salvage_from_inventory::<A, _, _>(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<bool> {
|
|
let mut has_empty_sockets = true;
|
|
|
|
let entity = world.entity(hero)?;
|
|
let inventory = entity.get_component::<Inventory<A>>()?;
|
|
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<A>,
|
|
&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::<AttributeSettings>(),
|
|
(&*hero_items, resources.get::<ItemSettings>()),
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn show_item_tooltip(
|
|
world: &mut World,
|
|
hero: Entity,
|
|
item_index: usize,
|
|
reference: &Weak<CharacterWindow>,
|
|
(x, y, w, _h): (i32, i32, u32, u32),
|
|
) -> Result<()> {
|
|
let entity = unsafe { remove_life_time(world.entity(hero)?) };
|
|
|
|
let inventory = entity.get_component::<Inventory<A>>()?;
|
|
let attributes = entity.get_component::<Attributes>()?;
|
|
|
|
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::<ItemSlotContainer>()?;
|
|
|
|
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<A: Ability + 'static> ContentUpdate for Content<A, Item> {
|
|
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::<A>();
|
|
|
|
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::<A>();
|
|
|
|
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::<A>();
|
|
|
|
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<A: Ability + 'static> Content<A, Jewel> {
|
|
fn show_jewel_tooltip(
|
|
world: &mut World,
|
|
hero: Entity,
|
|
item_index: usize,
|
|
reference: &Weak<CharacterWindow>,
|
|
(x, y, w, _h): (i32, i32, u32, u32),
|
|
) -> Result<()> {
|
|
let entity = unsafe { remove_life_time(world.entity(hero)?) };
|
|
let inventory = entity.get_component::<Inventory<A>>()?;
|
|
|
|
let target_x = x + w as i32;
|
|
let target_y = y;
|
|
|
|
let item_settings = world.resources.get_unchecked::<ItemSettings>();
|
|
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::<Inventory<A>>()?;
|
|
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::<Inventory<A>>()?;
|
|
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<A: Ability + 'static> ContentUpdate for Content<A, Jewel> {
|
|
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::<A>();
|
|
|
|
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::<A>();
|
|
|
|
inventory.update_page(world, true)?;
|
|
}
|
|
|
|
true
|
|
}
|
|
|
|
_ => false,
|
|
})
|
|
}
|
|
});
|
|
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
fn select(&self, world: &mut World) -> Result<()> {
|
|
self.select(world.resources.get_mut()?)
|
|
}
|
|
}
|
|
|
|
impl<A: Ability + 'static> ContentUpdate for Content<A, MapItem> {
|
|
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()?)
|
|
}
|
|
}
|