engine/character_window/src/inventory/jewel_right_side.rs

412 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,
},
items::{Item, ItemAffix, Jewel},
};
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(
game_handle: &GameHandle,
path: &str,
hero: Entity,
reference: &Weak<CharacterWindow>,
) -> Result<Self> {
let snippet = game_handle.gui_snippet(path)?;
let combine: Arc<Label> = snippet.element("combine")?;
combine.set_info_icon(&game_handle.controller_icon(ControllerButton::RightStick)?)?;
game_handle.upgrade().engine().on_scene_mut(|scene| {
scene
.resources
.insert_if_not_exists::<Option<ReferenceObject>>();
scene.resources.insert_if_not_exists::<LowerJewels>();
Ok(())
})?;
let me = Self { snippet };
me.setup_select(game_handle, hero, reference)?;
Ok(me)
}
fn setup_select(
&self,
game_handle: &GameHandle,
hero: Entity,
reference: &Weak<CharacterWindow>,
) -> Result<()> {
let (top, bottom) = self.elements()?;
top.set_select_callback({
let game_handle = game_handle.clone();
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();
let game = game_handle.upgrade();
let scene = game.engine().scene();
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(
&game_handle,
scene.entity(hero)?.get_component::<Attributes>()?,
(x + w as i32, y),
)?,
ReferenceObject::Jewel { jewel, .. } => jewel.create_tooltip(
&game_handle,
&game_handle.upgrade().item_settings,
(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({
let game_handle = game_handle.clone();
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();
let game = game_handle.upgrade();
let scene = game.engine().scene();
let lower_info = scene.resources.get::<LowerJewels>();
if let Some((lower_jewel, _)) = &lower_info.jewels[index] {
let tooltip = lower_jewel.create_tooltip(
&game_handle,
&game_handle.upgrade().item_settings,
(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({
let game_handle = game_handle.clone();
let reference = reference.clone();
move || {
let game = game_handle.upgrade();
let scene = game.engine().scene_mut();
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],
))
}
pub fn clear(game_handle: &GameHandle) {
let game = game_handle.upgrade();
let scene = game.engine().scene_mut();
*scene.resources.get_mut::<Option<ReferenceObject>>() = None;
scene
.resources
.get_mut::<LowerJewels>()
.jewels
.iter_mut()
.for_each(|j| *j = None);
}
pub fn combine(game_handle: &GameHandle, hero: Entity) -> Result<bool> {
let game = game_handle.upgrade();
let scene = game.engine().scene_mut();
let mut resources = unsafe { remove_life_time_mut(scene) }.resources.multi_mut();
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) => {
let inventory =
scene.entity_mut(hero)?.get_component_mut::<Inventory>()?;
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) => {
let entity = scene.entity_mut(hero)?;
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>()?;
statistics.update(attributes, &game.attribute_settings, &*item_slots);
}
}
}
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);
}
let entity = scene.entity_mut(hero)?;
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;
upper_jewel.update_stat(&game.item_settings);
upper_jewel.icon = Some(game.item_system().jewel_icon(
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 {
fn refresh(&mut self, game_handle: &GameHandle, _hero: Entity) -> Result<()> {
game_handle.upgrade().engine().on_scene(|scene| {
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(())
})
}
fn disable(&mut self, game_handle: &GameHandle, _hero: Entity) -> Result<()> {
let game = game_handle.upgrade();
let scene = game.engine().scene_mut();
*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
}
}