engine/character_window/src/inventory/jewel_right_side.rs

416 lines
14 KiB
Rust
Raw Normal View History

2024-08-25 12:30:03 +00:00
use rpg_components::{
components::{
attributes::Attributes,
inventory::{Inventory, Storable},
item_slots::ItemSlotContainer,
statistics::Statistics,
},
2024-08-26 09:22:59 +00:00
config::{attributes::AttributeSettings, items::ItemSettings},
items::{Item, ItemAffix, ItemSystem, Jewel},
2024-08-25 12:30:03 +00:00
};
use crate::*;
use std::{
cmp::Reverse,
sync::{Arc, Weak},
};
use crate::CharacterWindow;
use super::super::traits::*;
pub enum ReferenceItemSource {
Inventory(usize),
Slots(Option<usize>),
}
pub enum ReferenceObject {
Item {
item: Item,
source: ReferenceItemSource,
},
Jewel {
jewel: Jewel,
index: usize,
},
}
#[derive(Default)]
pub struct LowerJewels {
pub jewels: [Option<(Jewel, usize)>; 3],
}
pub struct JewelRightSide {
snippet: Arc<GuiSnippet>,
}
impl JewelRightSide {
pub fn new(
2024-08-26 08:08:03 +00:00
engine: &Arc<Engine>,
file: &str,
2024-08-25 12:30:03 +00:00
hero: Entity,
reference: &Weak<CharacterWindow>,
) -> Result<Self> {
2024-08-26 08:08:03 +00:00
let snippet = GuiSnippet::from_str(engine.gui_handler(), file)?;
2024-08-25 12:30:03 +00:00
let combine: Arc<Label> = snippet.element("combine")?;
2024-08-26 08:08:03 +00:00
combine.set_info_icon(&engine.controller_icon(ControllerButton::RightStick)?)?;
2024-08-25 12:30:03 +00:00
2024-08-26 08:08:03 +00:00
engine.on_scene_mut(|scene| {
2024-08-25 12:30:03 +00:00
scene
.resources
.insert_if_not_exists::<Option<ReferenceObject>>();
scene.resources.insert_if_not_exists::<LowerJewels>();
Ok(())
})?;
let me = Self { snippet };
2024-08-26 08:08:03 +00:00
me.setup_select(engine, hero, reference)?;
2024-08-25 12:30:03 +00:00
Ok(me)
}
fn setup_select(
&self,
2024-08-26 08:08:03 +00:00
engine: &Arc<Engine>,
2024-08-25 12:30:03 +00:00
hero: Entity,
reference: &Weak<CharacterWindow>,
) -> Result<()> {
let (top, bottom) = self.elements()?;
top.set_select_callback({
2024-08-26 08:08:03 +00:00
let engine = engine.clone();
2024-08-25 12:30:03 +00:00
let weak_top = Arc::downgrade(&top);
let reference = reference.clone();
move |selected| {
let menu = reference.upgrade().unwrap();
if selected {
let Some(button) = weak_top.upgrade() else {
return Ok(());
};
let (x, y, w, _h) = button.position_extent();
2024-08-26 08:08:03 +00:00
let scene = engine.scene();
2024-08-25 12:30:03 +00:00
let reference_info = scene.resources.get::<Option<ReferenceObject>>();
if let Some(reference_info) = reference_info {
let tooltip = match reference_info {
ReferenceObject::Item { item, .. } => item.create_tooltip(
2024-08-26 08:08:03 +00:00
engine.gui_handler(),
2024-08-25 12:30:03 +00:00
scene.entity(hero)?.get_component::<Attributes>()?,
(x + w as i32, y),
)?,
ReferenceObject::Jewel { jewel, .. } => jewel.create_tooltip(
2024-08-26 08:08:03 +00:00
engine.gui_handler(),
2024-08-26 09:22:59 +00:00
scene.resources.get::<ItemSettings>(),
2024-08-25 12:30:03 +00:00
(x + w as i32, y),
)?,
};
tooltip.enable()?;
tooltip.perform_single_check(x, y)?;
menu.add_tooltip("upper", tooltip);
}
} else {
menu.remove_tooltip("upper");
}
Ok(())
}
});
for (index, lower) in bottom.iter().enumerate() {
lower.set_select_callback({
2024-08-26 08:08:03 +00:00
let engine = engine.clone();
2024-08-25 12:30:03 +00:00
let weak_top = Arc::downgrade(&lower);
let reference = reference.clone();
move |selected| {
let menu = reference.upgrade().unwrap();
if selected {
let Some(button) = weak_top.upgrade() else {
return Ok(());
};
let (x, y, w, _h) = button.position_extent();
2024-08-26 08:08:03 +00:00
let scene = engine.scene();
2024-08-25 12:30:03 +00:00
let lower_info = scene.resources.get::<LowerJewels>();
if let Some((lower_jewel, _)) = &lower_info.jewels[index] {
let tooltip = lower_jewel.create_tooltip(
2024-08-26 08:08:03 +00:00
engine.gui_handler(),
2024-08-26 09:22:59 +00:00
scene.resources.get::<ItemSettings>(),
2024-08-25 12:30:03 +00:00
(x + w as i32, y),
)?;
tooltip.enable()?;
tooltip.perform_single_check(x, y)?;
menu.add_tooltip(format!("lower_{index}",), tooltip);
}
} else {
menu.remove_tooltip(format!("lower_{index}"));
}
Ok(())
}
});
lower.set_callback({
2024-08-26 08:08:03 +00:00
let engine = engine.clone();
2024-08-25 12:30:03 +00:00
let reference = reference.clone();
move || {
2024-08-26 08:08:03 +00:00
let scene = engine.scene_mut();
2024-08-25 12:30:03 +00:00
let lower_info = scene.resources.get_mut::<LowerJewels>();
if lower_info.jewels[index].is_some() {
lower_info.jewels[index] = None;
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
inventory.update_page(true)?;
}
}
Ok(())
}
});
}
Ok(())
}
fn elements(&self) -> Result<(Arc<Button>, [Arc<Button>; 3])> {
let reference_element: Arc<Button> = self.snippet.element("reference")?;
let first_element: Arc<Button> = self.snippet.element("first")?;
let second_element: Arc<Button> = self.snippet.element("second")?;
let third_element: Arc<Button> = self.snippet.element("third")?;
Ok((
reference_element,
[first_element, second_element, third_element],
))
}
2024-08-26 08:08:03 +00:00
pub fn clear(engine: &Arc<Engine>) {
let scene = engine.scene_mut();
2024-08-25 12:30:03 +00:00
*scene.resources.get_mut::<Option<ReferenceObject>>() = None;
scene
.resources
.get_mut::<LowerJewels>()
.jewels
.iter_mut()
.for_each(|j| *j = None);
}
2024-08-26 08:08:03 +00:00
pub fn combine(engine: &Arc<Engine>, hero: Entity) -> Result<bool> {
let scene = engine.scene_mut();
2024-08-26 09:22:59 +00:00
let (resources, entity) = scene.entity_resource(hero)?;
let mut resources = resources.multi_mut();
2024-08-25 12:30:03 +00:00
let reference_info = resources.get::<Option<ReferenceObject>>();
if reference_info.is_none() {
return Ok(false);
}
let lower_info = resources.get::<LowerJewels>();
if let Some(upper_info) = reference_info {
match upper_info {
ReferenceObject::Item { item, source } => {
// check that is there something in lower
// that can be socketed into the item
if !lower_info.jewels.iter().any(|jewel| jewel.is_some()) {
return Ok(false);
}
match source {
ReferenceItemSource::Inventory(index) => {
2024-08-26 09:22:59 +00:00
let inventory = entity.get_component_mut::<Inventory>()?;
2024-08-25 12:30:03 +00:00
let item = inventory.item_mut_at(*index);
match item.affixes.iter_mut().find(|affix| match affix {
ItemAffix::Socket(opt) => opt.is_none(),
ItemAffix::Stat(_) => false,
}) {
Some(ItemAffix::Socket(socket)) => {
// we already made sure that lower is not empty -> unwrap is safe
let (jewel, index) = lower_info.jewels[lower_info
.jewels
.iter()
.position(|jewel| jewel.is_some())
.unwrap()]
.take()
.unwrap();
*socket = Some(jewel);
inventory.remove_jewel(index);
}
_ => {
return Ok(false);
}
}
}
ReferenceItemSource::Slots(opt_index) => {
2024-08-26 09:22:59 +00:00
let attribute_settings = resources.get::<AttributeSettings>();
2024-08-26 11:29:24 +00:00
let item_settings = resources.get::<ItemSettings>();
2024-08-26 09:22:59 +00:00
2024-08-25 12:30:03 +00:00
let mut multi_mut = entity.multi_mut();
let inventory = multi_mut.get::<Inventory>()?;
let item_slots = multi_mut.get::<ItemSlotContainer>()?;
let slot = item.slot;
let item = item_slots.item_mut(slot, *opt_index).as_mut().unwrap();
match item.affixes.iter_mut().find(|affix| match affix {
ItemAffix::Socket(opt) => opt.is_none(),
ItemAffix::Stat(_) => false,
}) {
Some(ItemAffix::Socket(socket)) => {
// we already made sure that lower is not empty -> unwrap is safe
let (jewel, index) = lower_info.jewels[lower_info
.jewels
.iter()
.position(|jewel| jewel.is_some())
.unwrap()]
.take()
.unwrap();
*socket = Some(jewel);
inventory.remove_jewel(index);
}
_ => {
return Ok(false);
}
}
let statistics = multi_mut.get::<Statistics>()?;
let attributes = multi_mut.get::<Attributes>()?;
2024-08-26 11:29:24 +00:00
statistics.update(
attributes,
attribute_settings,
(&*item_slots, &*item_settings),
);
2024-08-25 12:30:03 +00:00
}
}
}
ReferenceObject::Jewel { jewel, index } => {
// check there are 3 jewels in lower
// and that all jewels match rarity and level
if !lower_info.jewels.iter().all(|j| match j {
Some((lower_jewel, _)) => {
jewel.rarity == lower_jewel.rarity && jewel.level == lower_jewel.level
}
None => false,
}) {
return Ok(false);
}
2024-08-26 09:22:59 +00:00
let item_settings = resources.get::<ItemSettings>();
let item_system = resources.get::<Arc<ItemSystem>>();
2024-08-25 12:30:03 +00:00
let inventory = entity.get_component_mut::<Inventory>()?;
let upper_jewel = inventory.jewel_mut_at(*index);
if upper_jewel.level >= 4 {
return Ok(false);
}
upper_jewel.level += 1;
2024-08-26 09:22:59 +00:00
upper_jewel.update_stat(item_settings);
upper_jewel.icon = Some(item_system.jewel_icon(
2024-08-25 12:30:03 +00:00
upper_jewel.rarity,
upper_jewel.level,
upper_jewel.attribute,
));
let mut jewels: Vec<(Jewel, usize)> = lower_info
.jewels
.iter_mut()
.map(|j| j.take().unwrap())
.collect();
jewels.sort_by_key(|(_, index)| Reverse(*index));
jewels.iter().for_each(|(jewel, i)| {
debug_assert_eq!(*jewel, inventory.remove_jewel(*i))
});
}
}
}
Ok(true)
}
}
impl RightSide for JewelRightSide {
2024-08-26 08:08:03 +00:00
fn refresh(&mut self, engine: &Engine, _hero: Entity) -> Result<()> {
engine.on_scene(|scene| {
2024-08-25 12:30:03 +00:00
let (reference, lower) = self.elements()?;
let reference_info = scene.resources.get::<Option<ReferenceObject>>();
let lower_info = scene.resources.get::<LowerJewels>();
match reference_info.as_ref() {
Some(reference_info) => {
let icon = match reference_info {
ReferenceObject::Item { item, .. } => item.icon(),
ReferenceObject::Jewel { jewel, .. } => jewel.icon(),
};
reference.set_icon(&icon)?;
}
None => reference.clear_icon()?,
}
for (jewel, icon) in lower_info.jewels.iter().zip(lower.iter()) {
match jewel.as_ref() {
Some((jewel, _)) => icon.set_icon(&jewel.icon())?,
None => icon.clear_icon()?,
}
}
Ok(())
})
}
2024-08-26 08:08:03 +00:00
fn disable(&mut self, engine: &Engine, _hero: Entity) -> Result<()> {
let scene = engine.scene_mut();
2024-08-25 12:30:03 +00:00
*scene.resources.get_mut::<Option<ReferenceObject>>() = None;
scene
.resources
.get_mut::<LowerJewels>()
.jewels
.iter_mut()
.for_each(|j| *j = None);
Ok(())
}
fn base(&self) -> &Arc<GuiSnippet> {
&self.snippet
}
}