2025-02-28 07:43:35 +00:00
|
|
|
use anyhow::Result;
|
|
|
|
use engine::prelude::*;
|
|
|
|
use paste;
|
|
|
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
config::{items::ItemSettings, save_game::SaveGame},
|
2025-04-05 10:16:34 +00:00
|
|
|
items::{Item, ItemAffix, ItemSlots, ItemSystem, Rarities, ability_book::Ability},
|
2025-02-28 07:43:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
use super::{
|
|
|
|
attributes::{Agility, Attribute, Attributes, Intelligence, Strength},
|
|
|
|
statistic_types::StatisticType,
|
|
|
|
};
|
|
|
|
|
|
|
|
macro_rules! load_item {
|
|
|
|
($me:ident, $var_name:ident, $slot:ident, $save_game:ident, $item_system:ident) => {
|
|
|
|
if $save_game.$var_name.used {
|
|
|
|
let attributes = Attributes::load(
|
|
|
|
$save_game.$var_name.strength,
|
|
|
|
$save_game.$var_name.agility,
|
|
|
|
$save_game.$var_name.intelligence,
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut $var_name = $item_system.item(
|
|
|
|
$save_game.$var_name.rarity,
|
|
|
|
ItemSlots::$slot,
|
|
|
|
$save_game.$var_name.level,
|
|
|
|
attributes,
|
|
|
|
$save_game.$var_name.affixes.clone(),
|
|
|
|
);
|
|
|
|
|
|
|
|
$var_name.affixes.iter_mut().for_each(|affix| {
|
|
|
|
if let ItemAffix::Socket(Some(jewel)) = affix {
|
|
|
|
jewel.icon =
|
|
|
|
Some($item_system.jewel_icon(jewel.rarity, jewel.level, jewel.attribute));
|
|
|
|
jewel.update_stat(&$item_system.item_settings);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$me.$var_name = Some($var_name);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
($me:ident, $var_name:ident, $index:expr, $slot:ident, $save_game:ident, $item_system:ident) => {
|
|
|
|
paste::expr! {
|
|
|
|
if $save_game.[<$var_name _ $index>].used {
|
|
|
|
let attributes = Attributes::load(
|
|
|
|
$save_game.[<$var_name _ $index>].strength,
|
|
|
|
$save_game.[<$var_name _ $index>].agility,
|
|
|
|
$save_game.[<$var_name _ $index>].intelligence,
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut $var_name = $item_system.item(
|
|
|
|
$save_game.[<$var_name _ $index>].rarity,
|
|
|
|
ItemSlots::$slot,
|
|
|
|
$save_game.[<$var_name _ $index>].level,
|
|
|
|
attributes,
|
|
|
|
$save_game.[<$var_name _ $index>].affixes.clone(),
|
|
|
|
);
|
|
|
|
|
|
|
|
$var_name.affixes.iter_mut().for_each(|affix| {
|
|
|
|
if let ItemAffix::Socket(Some(jewel)) = affix {
|
|
|
|
jewel.icon =
|
|
|
|
Some($item_system.jewel_icon(jewel.rarity, jewel.level, jewel.attribute));
|
|
|
|
jewel.update_stat(&$item_system.item_settings);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$me.[<$var_name s>][$index] = Some($var_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! store_item {
|
|
|
|
($me:ident, $save_game:ident, $var_name:ident) => {
|
|
|
|
match &$me.$var_name {
|
|
|
|
Some($var_name) => {
|
|
|
|
$save_game.$var_name.used = true;
|
|
|
|
$save_game.$var_name.level = $var_name.level;
|
|
|
|
$save_game.$var_name.strength = $var_name.attributes.strength().raw();
|
|
|
|
$save_game.$var_name.agility = $var_name.attributes.agility().raw();
|
|
|
|
$save_game.$var_name.intelligence = $var_name.attributes.intelligence().raw();
|
|
|
|
$save_game.$var_name.rarity = $var_name.rarity;
|
|
|
|
$save_game.$var_name.affixes = $var_name.affixes.clone();
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
$save_game.$var_name.used = false;
|
|
|
|
$save_game.$var_name.level = 0;
|
|
|
|
$save_game.$var_name.strength = 0;
|
|
|
|
$save_game.$var_name.agility = 0;
|
|
|
|
$save_game.$var_name.intelligence = 0;
|
|
|
|
$save_game.$var_name.rarity = Rarities::default();
|
|
|
|
$save_game.$var_name.affixes = Vec::new();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
($me:ident, $save_game:ident, $var_name:ident, $index:expr) => {
|
|
|
|
paste::expr! {
|
|
|
|
match &$me.[<$var_name s>][$index] {
|
|
|
|
Some($var_name) => {
|
|
|
|
$save_game.[<$var_name _ $index>].used = true;
|
|
|
|
$save_game.[<$var_name _ $index>].level = $var_name.level;
|
|
|
|
$save_game.[<$var_name _ $index>].strength = $var_name.attributes.strength().raw();
|
|
|
|
$save_game.[<$var_name _ $index>].agility = $var_name.attributes.agility().raw();
|
|
|
|
$save_game.[<$var_name _ $index>].intelligence = $var_name.attributes.intelligence().raw();
|
|
|
|
$save_game.[<$var_name _ $index>].rarity = $var_name.rarity;
|
|
|
|
$save_game.[<$var_name _ $index>].affixes = $var_name.affixes.clone();
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
$save_game.[<$var_name _ $index>].used = false;
|
|
|
|
$save_game.[<$var_name _ $index>].level = 0;
|
|
|
|
$save_game.[<$var_name _ $index>].strength = 0;
|
|
|
|
$save_game.[<$var_name _ $index>].agility = 0;
|
|
|
|
$save_game.[<$var_name _ $index>].intelligence = 0;
|
|
|
|
$save_game.[<$var_name _ $index>].rarity = Rarities::default();
|
|
|
|
$save_game.[<$var_name _ $index>].affixes = Vec::new();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! setter {
|
|
|
|
($item:ident) => {
|
|
|
|
paste::paste! {
|
2025-04-05 10:16:34 +00:00
|
|
|
fn [<set_ $item>](&mut self, $item: Option<Item>, entity: &mut EntityObject) {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.$item = $item;
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.[<apply_ $item _change>](entity).unwrap();
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub const RING_COUNT: usize = 4;
|
|
|
|
pub const AMULET_COUNT: usize = 2;
|
|
|
|
|
|
|
|
pub struct ItemSlotContainer {
|
|
|
|
// main slots
|
|
|
|
helmet: Option<Item>,
|
|
|
|
chest_plate: Option<Item>,
|
|
|
|
belt: Option<Item>,
|
|
|
|
gloves: Option<Item>,
|
|
|
|
boots: Option<Item>,
|
|
|
|
|
|
|
|
// hand slots
|
|
|
|
main_hand: Option<Item>,
|
|
|
|
off_hand: Option<Item>,
|
|
|
|
|
|
|
|
// jewelry slots
|
|
|
|
rings: [Option<Item>; RING_COUNT],
|
|
|
|
amulets: [Option<Item>; AMULET_COUNT],
|
|
|
|
|
|
|
|
slot_changed_callback: Option<
|
2025-04-05 10:16:34 +00:00
|
|
|
Box<dyn Fn(ItemSlots, Rarities, bool, &mut EntityObject) -> Result<()> + Send + Sync>,
|
2025-02-28 07:43:35 +00:00
|
|
|
>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ItemSlotContainer {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
helmet: None,
|
|
|
|
chest_plate: None,
|
|
|
|
belt: None,
|
|
|
|
gloves: None,
|
|
|
|
boots: None,
|
|
|
|
|
|
|
|
main_hand: None,
|
|
|
|
off_hand: None,
|
|
|
|
|
|
|
|
rings: [None, None, None, None],
|
|
|
|
amulets: [None, None],
|
|
|
|
|
|
|
|
slot_changed_callback: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load<A: Ability>(save_game: &SaveGame, item_system: &ItemSystem<A>) -> Result<Self> {
|
|
|
|
let mut me = Self::new();
|
|
|
|
|
|
|
|
load_item!(me, chest_plate, ChestPlate, save_game, item_system);
|
|
|
|
load_item!(me, helmet, Helmet, save_game, item_system);
|
|
|
|
load_item!(me, belt, Belt, save_game, item_system);
|
|
|
|
load_item!(me, gloves, Gloves, save_game, item_system);
|
|
|
|
load_item!(me, boots, Boots, save_game, item_system);
|
|
|
|
|
|
|
|
load_item!(me, main_hand, MainHand, save_game, item_system);
|
|
|
|
load_item!(me, off_hand, OffHand, save_game, item_system);
|
|
|
|
|
|
|
|
load_item!(me, ring, 0, Ring, save_game, item_system);
|
|
|
|
load_item!(me, ring, 1, Ring, save_game, item_system);
|
|
|
|
load_item!(me, ring, 2, Ring, save_game, item_system);
|
|
|
|
load_item!(me, ring, 3, Ring, save_game, item_system);
|
|
|
|
|
|
|
|
load_item!(me, amulet, 0, Amulet, save_game, item_system);
|
|
|
|
load_item!(me, amulet, 1, Amulet, save_game, item_system);
|
|
|
|
|
|
|
|
Ok(me)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store(&self, save_game: &mut SaveGame) {
|
|
|
|
store_item!(self, save_game, helmet);
|
|
|
|
store_item!(self, save_game, chest_plate);
|
|
|
|
store_item!(self, save_game, belt);
|
|
|
|
store_item!(self, save_game, gloves);
|
|
|
|
store_item!(self, save_game, boots);
|
|
|
|
|
|
|
|
store_item!(self, save_game, main_hand);
|
|
|
|
store_item!(self, save_game, off_hand);
|
|
|
|
|
|
|
|
store_item!(self, save_game, ring, 0);
|
|
|
|
store_item!(self, save_game, ring, 1);
|
|
|
|
store_item!(self, save_game, ring, 2);
|
|
|
|
store_item!(self, save_game, ring, 3);
|
|
|
|
|
|
|
|
store_item!(self, save_game, amulet, 0);
|
|
|
|
store_item!(self, save_game, amulet, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_vec(&self) -> Vec<&Option<Item>> {
|
|
|
|
vec![
|
|
|
|
&self.helmet,
|
|
|
|
&self.chest_plate,
|
|
|
|
&self.belt,
|
|
|
|
&self.gloves,
|
|
|
|
&self.boots,
|
|
|
|
&self.main_hand,
|
|
|
|
&self.off_hand,
|
|
|
|
&self.rings[0],
|
|
|
|
&self.rings[1],
|
|
|
|
&self.rings[2],
|
|
|
|
&self.rings[3],
|
|
|
|
&self.amulets[0],
|
|
|
|
&self.amulets[1],
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn _create_rarity_color_items(
|
|
|
|
item_meshes: HashMap<ItemSlots, AssetMesh>,
|
|
|
|
item_settings: &ItemSettings,
|
|
|
|
) -> Result<HashMap<ItemSlots, HashMap<Rarities, AssetMesh>>> {
|
|
|
|
let mut slot_meshes = HashMap::new();
|
|
|
|
|
|
|
|
for (slot, mesh) in item_meshes.into_iter() {
|
|
|
|
let mut rarity_meshes = HashMap::new();
|
|
|
|
|
|
|
|
for rarity in Rarities::iter() {
|
|
|
|
let mut copied_mesh = mesh.separated_copy()?;
|
|
|
|
let rarity_color = item_settings.rarity_color_settings.from_rarity(*rarity);
|
|
|
|
|
|
|
|
let buffers = copied_mesh
|
|
|
|
.primitive_types
|
|
|
|
.iter()
|
|
|
|
.map(|primitive| match primitive {
|
|
|
|
PrimitiveDataTypes::PositionNormalColorUVBone(data) => {
|
|
|
|
data.remove_uv_from_buffer()
|
|
|
|
}
|
|
|
|
PrimitiveDataTypes::PositionNormalBone(d) => Ok(d.vertex_buffer.clone()),
|
|
|
|
|
|
|
|
PrimitiveDataTypes::PositionOnly(_) => todo!(),
|
|
|
|
PrimitiveDataTypes::PositionNormal(_) => todo!(),
|
|
|
|
PrimitiveDataTypes::PositionNormalColor(_) => todo!(),
|
|
|
|
PrimitiveDataTypes::PositionColorUV(_) => todo!(),
|
|
|
|
PrimitiveDataTypes::PositionNormalColorUV(_) => todo!(),
|
|
|
|
PrimitiveDataTypes::PositionNormalColorUVNormalUV(_) => todo!(),
|
|
|
|
PrimitiveDataTypes::PositionNormalColorUVNormalUVBone(_) => todo!(),
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<_>>>()?;
|
|
|
|
|
|
|
|
copied_mesh.primitive_types.clear();
|
|
|
|
|
|
|
|
buffers.into_iter().try_for_each(|buffer| {
|
|
|
|
copied_mesh.add_primitive(
|
|
|
|
buffer,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
PrimitiveMaterial {
|
|
|
|
color: {
|
|
|
|
let c: [f32; 3] = rarity_color.into();
|
|
|
|
[c[0], c[1], c[2], 1.0]
|
|
|
|
},
|
|
|
|
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
})?;
|
|
|
|
|
|
|
|
rarity_meshes.insert(*rarity, copied_mesh);
|
|
|
|
}
|
|
|
|
|
|
|
|
slot_meshes.insert(slot, rarity_meshes);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(slot_meshes)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_item_change_callback(
|
|
|
|
&mut self,
|
|
|
|
_draw: &mut Draw,
|
|
|
|
_location: &Location,
|
|
|
|
) -> Result<()> {
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// item_meshes: if query_meshes {
|
|
|
|
// Arc::new(
|
|
|
|
// Self::find_items(draw)
|
|
|
|
// .map({
|
|
|
|
// let item_settings = item_settings.clone();
|
|
|
|
|
|
|
|
// move |item_meshes| {
|
|
|
|
// Self::create_rarity_color_items(item_meshes, &item_settings)
|
|
|
|
// }
|
|
|
|
// })
|
|
|
|
// .transpose()?
|
|
|
|
// .unwrap_or_default(),
|
|
|
|
// )
|
|
|
|
// } else {
|
|
|
|
// Default::default()
|
|
|
|
// },
|
|
|
|
|
|
|
|
// let item_rarity_meshes = self.item_meshes.clone();
|
|
|
|
|
|
|
|
// // only enable items that are equipped
|
|
|
|
// self.slot_changed_callback = Some(Box::new(move |slot, rarity, is_some, multi_mut| {
|
|
|
|
// Self::equipment_changed(multi_mut, &item_rarity_meshes, slot, rarity, is_some)
|
|
|
|
// }));
|
|
|
|
|
|
|
|
// Self::check_items(draw, location, self, &self.item_meshes)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
setter!(helmet);
|
|
|
|
setter!(belt);
|
|
|
|
setter!(chest_plate);
|
|
|
|
setter!(gloves);
|
|
|
|
setter!(boots);
|
|
|
|
setter!(main_hand);
|
|
|
|
setter!(off_hand);
|
|
|
|
|
|
|
|
fn set_rings(&mut self, ring: Option<Item>, index: usize) {
|
|
|
|
self.rings[index] = ring;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_amulets(&mut self, amulet: Option<Item>, index: usize) {
|
|
|
|
self.amulets[index] = amulet;
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn apply_helmet_change(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.apply_item_change(
|
|
|
|
ItemSlots::Helmet,
|
|
|
|
match &self.helmet {
|
|
|
|
Some(helmet) => helmet.rarity,
|
|
|
|
None => Rarities::Common,
|
|
|
|
},
|
|
|
|
self.helmet.is_some(),
|
2025-04-05 10:16:34 +00:00
|
|
|
entity,
|
2025-02-28 07:43:35 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn apply_belt_change(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.apply_item_change(
|
|
|
|
ItemSlots::Belt,
|
|
|
|
match &self.belt {
|
|
|
|
Some(belt) => belt.rarity,
|
|
|
|
None => Rarities::Common,
|
|
|
|
},
|
|
|
|
self.belt.is_some(),
|
2025-04-05 10:16:34 +00:00
|
|
|
entity,
|
2025-02-28 07:43:35 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn apply_chest_plate_change(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.apply_item_change(
|
|
|
|
ItemSlots::ChestPlate,
|
|
|
|
match &self.chest_plate {
|
|
|
|
Some(chest_plate) => chest_plate.rarity,
|
|
|
|
None => Rarities::Common,
|
|
|
|
},
|
|
|
|
self.chest_plate.is_some(),
|
2025-04-05 10:16:34 +00:00
|
|
|
entity,
|
2025-02-28 07:43:35 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn apply_gloves_change(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.apply_item_change(
|
|
|
|
ItemSlots::Gloves,
|
|
|
|
match &self.gloves {
|
|
|
|
Some(gloves) => gloves.rarity,
|
|
|
|
None => Rarities::Common,
|
|
|
|
},
|
|
|
|
self.gloves.is_some(),
|
2025-04-05 10:16:34 +00:00
|
|
|
entity,
|
2025-02-28 07:43:35 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn apply_boots_change(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.apply_item_change(
|
|
|
|
ItemSlots::Boots,
|
|
|
|
match &self.boots {
|
|
|
|
Some(boots) => boots.rarity,
|
|
|
|
None => Rarities::Common,
|
|
|
|
},
|
|
|
|
self.boots.is_some(),
|
2025-04-05 10:16:34 +00:00
|
|
|
entity,
|
2025-02-28 07:43:35 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn apply_main_hand_change(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.apply_item_change(
|
|
|
|
ItemSlots::MainHand,
|
|
|
|
match &self.main_hand {
|
|
|
|
Some(main_hand) => main_hand.rarity,
|
|
|
|
None => Rarities::Common,
|
|
|
|
},
|
|
|
|
self.main_hand.is_some(),
|
2025-04-05 10:16:34 +00:00
|
|
|
entity,
|
2025-02-28 07:43:35 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn apply_off_hand_change(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
self.apply_item_change(
|
|
|
|
ItemSlots::OffHand,
|
|
|
|
match &self.off_hand {
|
|
|
|
Some(off_hand) => off_hand.rarity,
|
|
|
|
None => Rarities::Common,
|
|
|
|
},
|
|
|
|
self.off_hand.is_some(),
|
2025-04-05 10:16:34 +00:00
|
|
|
entity,
|
2025-02-28 07:43:35 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn apply_item_change(
|
|
|
|
&self,
|
|
|
|
item_slot: ItemSlots,
|
|
|
|
rarity: Rarities,
|
|
|
|
is_some: bool,
|
2025-04-05 10:16:34 +00:00
|
|
|
entity: &mut EntityObject,
|
2025-02-28 07:43:35 +00:00
|
|
|
) -> Result<()> {
|
|
|
|
if let Some(slot_changed_callback) = &self.slot_changed_callback {
|
2025-04-05 10:16:34 +00:00
|
|
|
slot_changed_callback(item_slot, rarity, is_some, entity)?;
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// getter
|
|
|
|
impl ItemSlotContainer {
|
|
|
|
pub fn helmet(&self) -> &Option<Item> {
|
|
|
|
&self.helmet
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn chest(&self) -> &Option<Item> {
|
|
|
|
&self.chest_plate
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn belt(&self) -> &Option<Item> {
|
|
|
|
&self.belt
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn gloves(&self) -> &Option<Item> {
|
|
|
|
&self.gloves
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn boots(&self) -> &Option<Item> {
|
|
|
|
&self.boots
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn primary_hand(&self) -> &Option<Item> {
|
|
|
|
&self.main_hand
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn secondary_hand(&self) -> &Option<Item> {
|
|
|
|
&self.off_hand
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ring(&self, index: usize) -> &Option<Item> {
|
|
|
|
&self.rings[index]
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn amulet(&self, index: usize) -> &Option<Item> {
|
|
|
|
&self.amulets[index]
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn item_mut(&mut self, slot: ItemSlots, index: Option<usize>) -> &mut Option<Item> {
|
|
|
|
match slot {
|
|
|
|
ItemSlots::Helmet => &mut self.helmet,
|
|
|
|
ItemSlots::ChestPlate => &mut self.chest_plate,
|
|
|
|
ItemSlots::Belt => &mut self.belt,
|
|
|
|
ItemSlots::Gloves => &mut self.gloves,
|
|
|
|
ItemSlots::Boots => &mut self.boots,
|
|
|
|
ItemSlots::Ring => &mut self.rings[index.unwrap()],
|
|
|
|
ItemSlots::Amulet => &mut self.amulets[index.unwrap()],
|
|
|
|
ItemSlots::MainHand => &mut self.main_hand,
|
|
|
|
ItemSlots::OffHand => &mut self.off_hand,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// setter
|
|
|
|
impl ItemSlotContainer {
|
2025-04-05 10:16:34 +00:00
|
|
|
fn _update_helmet(&mut self, helmet: Item, entity: &mut EntityObject) {
|
2025-02-28 07:43:35 +00:00
|
|
|
debug_assert!(helmet.slot == ItemSlots::Helmet);
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_helmet(Some(helmet), entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
pub fn unset_helmet(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
if self.helmet.is_some() {
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_helmet(None, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn update_chest(&mut self, chest: Item, entity: &mut EntityObject) {
|
2025-02-28 07:43:35 +00:00
|
|
|
debug_assert!(chest.slot == ItemSlots::ChestPlate);
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_chest_plate(Some(chest), entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
pub fn unset_chest(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
if self.chest_plate.is_some() {
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_chest_plate(None, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn _update_belt(&mut self, belt: Item, entity: &mut EntityObject) {
|
2025-02-28 07:43:35 +00:00
|
|
|
debug_assert!(belt.slot == ItemSlots::Belt);
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_belt(Some(belt), entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
pub fn unset_belt(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
if self.belt.is_some() {
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_belt(None, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn _update_gloves(&mut self, gloves: Item, entity: &mut EntityObject) {
|
2025-02-28 07:43:35 +00:00
|
|
|
debug_assert!(gloves.slot == ItemSlots::Gloves);
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_gloves(Some(gloves), entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
pub fn unset_gloves(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
if self.gloves.is_some() {
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_gloves(None, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn _update_boots(&mut self, boots: Item, entity: &mut EntityObject) {
|
2025-02-28 07:43:35 +00:00
|
|
|
debug_assert!(boots.slot == ItemSlots::Boots);
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_boots(Some(boots), entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
pub fn unset_boots(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
if self.boots.is_some() {
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_boots(None, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn update_primary_hand(&mut self, primary_hand: Item, entity: &mut EntityObject) {
|
2025-02-28 07:43:35 +00:00
|
|
|
debug_assert!(primary_hand.slot == ItemSlots::MainHand);
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_main_hand(Some(primary_hand), entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
pub fn unset_primary_hand(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
if self.main_hand.is_some() {
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_main_hand(None, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
fn update_secondary_hand(&mut self, secondary_hand: Item, entity: &mut EntityObject) {
|
2025-02-28 07:43:35 +00:00
|
|
|
debug_assert!(secondary_hand.slot == ItemSlots::OffHand);
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_off_hand(Some(secondary_hand), entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
pub fn unset_secondary_hand(&mut self, entity: &mut EntityObject) -> Result<()> {
|
2025-02-28 07:43:35 +00:00
|
|
|
if self.off_hand.is_some() {
|
2025-04-05 10:16:34 +00:00
|
|
|
self.set_off_hand(None, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unset_ring(&mut self, index: usize) -> Result<()> {
|
|
|
|
if self.rings[index].is_some() {
|
|
|
|
self.set_rings(None, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unset_amulet(&mut self, index: usize) -> Result<()> {
|
|
|
|
if self.amulets[index].is_some() {
|
|
|
|
self.set_amulets(None, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ItemSlotContainer {
|
|
|
|
#[inline]
|
|
|
|
fn _item(
|
|
|
|
item_meshes: &mut HashMap<ItemSlots, AssetMesh>,
|
|
|
|
mesh: &AssetMesh,
|
|
|
|
name: &str,
|
|
|
|
slot: ItemSlots,
|
|
|
|
) {
|
|
|
|
if let Some(mesh_name) = &mesh.name {
|
|
|
|
if name == mesh_name {
|
|
|
|
assert!(item_meshes.insert(slot, mesh.clone()).is_none());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn _find_items(draw: &Draw) -> Option<HashMap<ItemSlots, AssetMesh>> {
|
|
|
|
let mut item_meshes = HashMap::new();
|
|
|
|
|
|
|
|
for mesh in draw.iter() {
|
|
|
|
Self::_item(&mut item_meshes, mesh, "Helmet", ItemSlots::Helmet);
|
|
|
|
Self::_item(&mut item_meshes, mesh, "Shield", ItemSlots::OffHand);
|
|
|
|
Self::_item(&mut item_meshes, mesh, "Sword", ItemSlots::MainHand);
|
|
|
|
Self::_item(&mut item_meshes, mesh, "ChestPlate", ItemSlots::ChestPlate);
|
|
|
|
Self::_item(&mut item_meshes, mesh, "Boots", ItemSlots::Boots);
|
|
|
|
Self::_item(&mut item_meshes, mesh, "Gloves", ItemSlots::Gloves);
|
|
|
|
}
|
|
|
|
|
|
|
|
if !item_meshes.is_empty() {
|
|
|
|
Some(item_meshes)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn _undress(draw: &mut Draw, name: &str) {
|
|
|
|
draw.remove_by_name(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn _dress(
|
|
|
|
draw: &mut Draw,
|
|
|
|
location: &Location,
|
|
|
|
item_meshes: &HashMap<ItemSlots, HashMap<Rarities, AssetMesh>>,
|
|
|
|
name: &str,
|
|
|
|
slot: ItemSlots,
|
|
|
|
rarity: Rarities,
|
|
|
|
) -> Result<()> {
|
|
|
|
// check that the item is not already equipped
|
|
|
|
if !draw.contains(name) {
|
|
|
|
match item_meshes
|
|
|
|
.get(&slot)
|
|
|
|
.map(|rarity_items| rarity_items.get(&rarity))
|
|
|
|
.flatten()
|
|
|
|
{
|
|
|
|
Some(mesh) => {
|
|
|
|
mesh.model_buffer()
|
|
|
|
.fill(&[(location.transformation_matrix() * mesh.model_matrix()).into()])?;
|
|
|
|
|
|
|
|
draw.push(mesh.clone());
|
|
|
|
}
|
|
|
|
None => println!("couldnt find {:?} in item_meshes", slot),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn _check_items(
|
|
|
|
draw: &mut Draw,
|
|
|
|
location: &Location,
|
|
|
|
items: &ItemSlotContainer,
|
|
|
|
item_meshes: &HashMap<ItemSlots, HashMap<Rarities, AssetMesh>>,
|
|
|
|
) -> Result<()> {
|
|
|
|
macro_rules! check {
|
|
|
|
($func:ident, $name:expr) => {
|
|
|
|
match items.$func() {
|
|
|
|
Some(item) => {
|
|
|
|
Self::_dress(draw, location, item_meshes, $name, item.slot, item.rarity)?;
|
|
|
|
}
|
|
|
|
None => Self::_undress(draw, $name),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
check!(primary_hand, "Sword");
|
|
|
|
check!(secondary_hand, "Shield");
|
|
|
|
check!(helmet, "Helmet");
|
|
|
|
check!(chest, "ChestPlate");
|
|
|
|
check!(boots, "Boots");
|
|
|
|
check!(gloves, "Gloves");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn _equipment_changed(
|
2025-04-05 10:16:34 +00:00
|
|
|
entity: &mut EntityObject,
|
2025-02-28 07:43:35 +00:00
|
|
|
item_meshes: &HashMap<ItemSlots, HashMap<Rarities, AssetMesh>>,
|
|
|
|
slot: ItemSlots,
|
|
|
|
rarity: Rarities,
|
|
|
|
is_some: bool,
|
|
|
|
) -> Result<()> {
|
2025-04-05 10:16:34 +00:00
|
|
|
let (draw, location): (&mut Draw, &mut Location) = entity.get_components_mut()?;
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
let item_name = match slot {
|
|
|
|
ItemSlots::Helmet => "Helmet",
|
|
|
|
ItemSlots::ChestPlate => "ChestPlate",
|
|
|
|
ItemSlots::Gloves => "Gloves",
|
|
|
|
ItemSlots::MainHand => "Sword",
|
|
|
|
ItemSlots::OffHand => "Shield",
|
|
|
|
ItemSlots::Boots => "Boots",
|
|
|
|
|
|
|
|
ItemSlots::Belt => return Ok(()),
|
|
|
|
ItemSlots::Ring => return Ok(()),
|
|
|
|
ItemSlots::Amulet => return Ok(()),
|
|
|
|
};
|
|
|
|
|
|
|
|
if is_some {
|
|
|
|
Self::_dress(draw, location, item_meshes, item_name, slot, rarity)?;
|
|
|
|
} else {
|
|
|
|
Self::_undress(draw, item_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ItemSlotContainer {
|
|
|
|
pub fn has_space_for(&self, item: &Item) -> bool {
|
|
|
|
match item.slot {
|
|
|
|
ItemSlots::Helmet => self.helmet.is_none(),
|
|
|
|
ItemSlots::ChestPlate => self.chest_plate.is_none(),
|
|
|
|
ItemSlots::Belt => self.belt.is_none(),
|
|
|
|
ItemSlots::Gloves => self.gloves.is_none(),
|
|
|
|
ItemSlots::Boots => self.boots.is_none(),
|
|
|
|
ItemSlots::Ring => {
|
|
|
|
for i in 0..RING_COUNT {
|
|
|
|
if self.rings[i].is_none() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
ItemSlots::Amulet => {
|
|
|
|
for i in 0..AMULET_COUNT {
|
|
|
|
if self.amulets[i].is_none() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
ItemSlots::MainHand => self.main_hand.is_none(),
|
|
|
|
ItemSlots::OffHand => self.off_hand.is_none(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// inserts the item, returns the current item at this slot
|
|
|
|
pub fn insert(
|
|
|
|
&mut self,
|
|
|
|
item: Item,
|
|
|
|
attributes: &Attributes,
|
2025-04-05 10:16:34 +00:00
|
|
|
entity: &mut EntityObject,
|
2025-02-28 07:43:35 +00:00
|
|
|
) -> Result<Option<Item>> {
|
|
|
|
// check attribute requirements
|
|
|
|
if attributes < &item.attributes {
|
|
|
|
return Ok(Some(item));
|
|
|
|
}
|
|
|
|
|
2025-04-05 10:16:34 +00:00
|
|
|
self.insert_unchecked(item, entity)
|
2025-02-28 07:43:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_unchecked(
|
|
|
|
&mut self,
|
|
|
|
item: Item,
|
2025-04-05 10:16:34 +00:00
|
|
|
entity: &mut EntityObject,
|
2025-02-28 07:43:35 +00:00
|
|
|
) -> Result<Option<Item>> {
|
|
|
|
Ok(match item.slot {
|
|
|
|
ItemSlots::Helmet => {
|
|
|
|
let current_helmet = self.helmet.clone();
|
2025-04-05 10:16:34 +00:00
|
|
|
self._update_helmet(item, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
current_helmet
|
|
|
|
}
|
|
|
|
ItemSlots::ChestPlate => {
|
|
|
|
let current_chest_plate = self.chest_plate.clone();
|
2025-04-05 10:16:34 +00:00
|
|
|
self.update_chest(item, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
current_chest_plate
|
|
|
|
}
|
|
|
|
ItemSlots::Belt => {
|
|
|
|
let current_belt = self.belt.clone();
|
2025-04-05 10:16:34 +00:00
|
|
|
self._update_belt(item, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
current_belt
|
|
|
|
}
|
|
|
|
ItemSlots::Gloves => {
|
|
|
|
let current_gloves = self.gloves.clone();
|
2025-04-05 10:16:34 +00:00
|
|
|
self._update_gloves(item, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
current_gloves
|
|
|
|
}
|
|
|
|
ItemSlots::Boots => {
|
|
|
|
let current_boots = self.boots.clone();
|
2025-04-05 10:16:34 +00:00
|
|
|
self._update_boots(item, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
current_boots
|
|
|
|
}
|
|
|
|
ItemSlots::Ring => {
|
|
|
|
if let Some(index) = self.rings.iter().position(|ring| ring.is_none()) {
|
|
|
|
self.set_rings(Some(item), index);
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
// return first ring, if there is no slot left
|
|
|
|
let current_ring = self.rings[0].clone();
|
|
|
|
self.set_rings(Some(item), 0);
|
|
|
|
|
|
|
|
return Ok(current_ring);
|
|
|
|
}
|
|
|
|
ItemSlots::Amulet => {
|
|
|
|
if let Some(index) = self.amulets.iter().position(|amulet| amulet.is_none()) {
|
|
|
|
self.set_amulets(Some(item), index);
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
// return first amulet, if there is no slot left
|
|
|
|
let current_amulet = self.amulets[0].clone();
|
|
|
|
self.set_amulets(Some(item), 0);
|
|
|
|
|
|
|
|
return Ok(current_amulet);
|
|
|
|
}
|
|
|
|
ItemSlots::MainHand => {
|
|
|
|
let current_main_hand = self.main_hand.clone();
|
2025-04-05 10:16:34 +00:00
|
|
|
self.update_primary_hand(item, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
current_main_hand
|
|
|
|
}
|
|
|
|
ItemSlots::OffHand => {
|
|
|
|
let current_off_hand = self.off_hand.clone();
|
2025-04-05 10:16:34 +00:00
|
|
|
self.update_secondary_hand(item, entity);
|
2025-02-28 07:43:35 +00:00
|
|
|
|
|
|
|
current_off_hand
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn item_at(&self, slot: ItemSlots) -> Option<&Item> {
|
|
|
|
match slot {
|
|
|
|
ItemSlots::Helmet => self.helmet().as_ref(),
|
|
|
|
ItemSlots::ChestPlate => self.chest().as_ref(),
|
|
|
|
ItemSlots::Belt => self.belt().as_ref(),
|
|
|
|
ItemSlots::Gloves => self.gloves().as_ref(),
|
|
|
|
ItemSlots::Boots => self.boots().as_ref(),
|
|
|
|
ItemSlots::Ring => {
|
|
|
|
for ring in self.rings.iter() {
|
|
|
|
if ring.is_some() {
|
|
|
|
return ring.as_ref();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
ItemSlots::Amulet => {
|
|
|
|
for amulet in self.amulets.iter() {
|
|
|
|
if amulet.is_some() {
|
|
|
|
return amulet.as_ref();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
ItemSlots::MainHand => self.primary_hand().as_ref(),
|
|
|
|
ItemSlots::OffHand => self.secondary_hand().as_ref(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn collect_attribute_bonuses(
|
|
|
|
&self,
|
|
|
|
item_settings: &ItemSettings,
|
|
|
|
) -> (Strength, Agility, Intelligence) {
|
|
|
|
let mut strength = Strength::default();
|
|
|
|
let mut agility = Agility::default();
|
|
|
|
let mut intelligence = Intelligence::default();
|
|
|
|
|
|
|
|
for item in self.as_vec().iter().copied().flatten() {
|
|
|
|
for affix in item.affixes.iter() {
|
|
|
|
if let ItemAffix::Socket(Some(jewel)) = affix {
|
|
|
|
let value = item_settings
|
|
|
|
.jewel_rarity_multiplier
|
|
|
|
.from_rarity(jewel.rarity)
|
|
|
|
* jewel.level
|
|
|
|
* item_settings.general.jewel_level_multiplier;
|
|
|
|
|
|
|
|
match jewel.attribute {
|
|
|
|
Attribute::Agility => agility += Agility::from(value),
|
|
|
|
Attribute::Intelligence => intelligence += Intelligence::from(value),
|
|
|
|
Attribute::Strength => strength += Strength::from(value),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(strength, agility, intelligence)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn collect_stat_bonuses(&self) -> Vec<StatisticType> {
|
|
|
|
let mut affixes = Vec::new();
|
|
|
|
let items = self.as_vec();
|
|
|
|
|
|
|
|
for item in items.iter().copied().flatten() {
|
|
|
|
for affix in item.affixes.iter() {
|
|
|
|
affixes.push(affix.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Self::squash_stats(affixes)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn squash_stats(affixes: Vec<ItemAffix>) -> Vec<StatisticType> {
|
|
|
|
let mut result = Vec::new();
|
|
|
|
|
|
|
|
for stat in affixes.iter() {
|
|
|
|
match stat {
|
|
|
|
ItemAffix::Socket(jewel) => {
|
|
|
|
if let Some(jewel) = jewel {
|
|
|
|
Self::insert_stat(&jewel.stat, &mut result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ItemAffix::Stat(stat) => Self::insert_stat(stat, &mut result),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
fn insert_stat(val: &StatisticType, vec: &mut Vec<StatisticType>) {
|
|
|
|
match vec
|
|
|
|
.iter_mut()
|
|
|
|
.find(|stat| StatisticType::same_type(stat, val))
|
|
|
|
{
|
|
|
|
Some(stat) => {
|
|
|
|
*stat += val.clone();
|
|
|
|
}
|
|
|
|
None => vec.push(val.clone()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EntityComponent for ItemSlotContainer {
|
|
|
|
fn name(&self) -> &str {
|
|
|
|
Self::debug_name()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ComponentDebug for ItemSlotContainer {
|
|
|
|
fn debug_name() -> &'static str {
|
|
|
|
"ItemSlotContainer"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
use anyhow::Result;
|
|
|
|
use assetpath::AssetPath;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn create_rarity_textures() -> Result<()> {
|
|
|
|
const OBJECT_PATH: &str = "gltf_objects/blender_test/blender_test.glb";
|
|
|
|
|
|
|
|
let path = AssetPath::from((std::env::var("GAVANIA_DATA_DIR").unwrap(), OBJECT_PATH));
|
|
|
|
|
|
|
|
let (device, queue) = create_vk_handles()?;
|
|
|
|
|
|
|
|
let gltf_asset = GltfAsset::new(&path)?;
|
|
|
|
let asset = Asset::new(
|
|
|
|
&device,
|
|
|
|
&queue,
|
|
|
|
SceneType::Rasterizer,
|
|
|
|
gltf_asset,
|
|
|
|
path.path_without_prefix(),
|
|
|
|
)?;
|
|
|
|
|
|
|
|
if std::path::Path::new("mesh_images").exists() {
|
|
|
|
std::fs::remove_dir_all("mesh_images")?;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !std::path::Path::new("mesh_images").exists() {
|
|
|
|
std::fs::create_dir("mesh_images")?;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (x, mesh) in asset.meshes.iter().enumerate() {
|
|
|
|
for (y, primitive_type) in mesh.primitive_types.iter().enumerate() {
|
|
|
|
if let Some(image) = primitive_type.color_texture() {
|
|
|
|
image.to_file(&format!("mesh_images/{}_{}_source.png", x, y))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|