Use generic ability

This commit is contained in:
hodasemi 2024-08-27 14:06:06 +02:00
parent fc409187df
commit 8e2ed3e5c2
28 changed files with 262 additions and 274 deletions

View file

@ -1,3 +1,4 @@
use std::marker::PhantomData;
use std::sync::{Arc, Weak};
use rpg_components::components::ability_slots::AbilitySlots;
@ -11,13 +12,15 @@ use crate::*;
use crate::{traits::RightSide, CharacterWindow};
pub struct AbilityPageRightSide {
pub struct AbilityPageRightSide<A: Ability + 'static> {
snippet: Arc<GuiSnippet>,
ability_index: usize,
ability_marker: PhantomData<A>,
}
impl AbilityPageRightSide {
impl<A: Ability + 'static> AbilityPageRightSide<A> {
const ABILITY_BUTTON_NAMES: [&'static str; 4] = [
"first_ability",
"second_ability",
@ -59,7 +62,7 @@ impl AbilityPageRightSide {
move || {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let abilities = tabs.abilities();
let abilities = tabs.abilities::<A>();
abilities.right_side.ability_index = index;
abilities.update_page()?;
@ -79,7 +82,7 @@ impl AbilityPageRightSide {
if selected {
engine.on_scene(|scene| {
let entity = scene.entity(hero)?;
let abilities = entity.get_component::<AbilitySlots>()?;
let abilities = entity.get_component::<AbilitySlots<A>>()?;
if let Some(book) = abilities.book(index) {
let button = weak_button.upgrade().unwrap();
@ -122,7 +125,7 @@ impl AbilityPageRightSide {
let entity = scene.entity_mut(hero)?;
let mut multi_mut = entity.multi_mut();
let abilities = multi_mut.get::<AbilitySlots>()?;
let abilities = multi_mut.get::<AbilitySlots<A>>()?;
if let Some(ability) = abilities.book_mut(index) {
let materials = multi_mut.get::<CraftingMaterials>()?;
@ -131,7 +134,7 @@ impl AbilityPageRightSide {
if let Some(menu) = reference.upgrade() {
menu.tabs_mut()
.abilities()
.abilities::<A>()
.right_side
.refresh(&engine, hero)?;
}
@ -151,6 +154,7 @@ impl AbilityPageRightSide {
Ok(Self {
snippet,
ability_index: 0,
ability_marker: PhantomData,
})
}
@ -189,7 +193,7 @@ impl AbilityPageRightSide {
Ok(())
}
fn update_active_ability(&self, engine: &Engine, abilities: &AbilitySlots) -> Result<()> {
fn update_active_ability(&self, engine: &Engine, abilities: &AbilitySlots<A>) -> Result<()> {
let grid: Arc<Grid> = self.snippet.element("ability_content")?;
let (_, rows) = grid.dimensions();
@ -237,7 +241,7 @@ impl AbilityPageRightSide {
}
}
impl RightSide for AbilityPageRightSide {
impl<A: Ability + 'static> RightSide for AbilityPageRightSide<A> {
fn refresh(&mut self, engine: &Engine, hero: Entity) -> Result<()> {
engine.on_scene(|scene| {
let entity = scene.entity(hero)?;
@ -251,7 +255,7 @@ impl RightSide for AbilityPageRightSide {
self.update_crafting_count("epic", crafting.count(Rarities::Epic))?;
self.update_crafting_count("legendary", crafting.count(Rarities::Legendary))?;
let abilities = entity.get_component::<AbilitySlots>()?;
let abilities = entity.get_component::<AbilitySlots<A>>()?;
for (index, name) in Self::ABILITY_BUTTON_NAMES.iter().enumerate() {
self.update_ability_icon(name, abilities.book(index).map(|book| book.icon()))?;

View file

@ -15,7 +15,7 @@ use crate::{
use super::AbilityPage;
impl Content<AbilityAddon> {
impl<A: Ability + 'static> Content<A, AbilityAddon> {
fn show_addon_tooltip(
engine: &Arc<Engine>,
hero: Entity,
@ -25,7 +25,7 @@ impl Content<AbilityAddon> {
) -> Result<()> {
engine.on_scene(|scene| {
let entity = scene.entity(hero)?;
let inventory = entity.get_component::<Inventory>()?;
let inventory = entity.get_component::<Inventory<A>>()?;
let target_x = x + w as i32;
let target_y = y;
@ -46,14 +46,14 @@ impl Content<AbilityAddon> {
engine: &Arc<Engine>,
hero: Entity,
addon_index: usize,
ability_page: &AbilityPage,
ability_page: &AbilityPage<A>,
) -> Result<()> {
engine.on_scene_mut(|scene| {
let entity = scene.entity_mut(hero)?;
let mut multi_mut = entity.multi_mut();
let inventory = multi_mut.get::<Inventory>()?;
let abilities = multi_mut.get::<AbilitySlots>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
let abilities = multi_mut.get::<AbilitySlots<A>>()?;
if let Some(book) = abilities.book_mut(ability_page.right_side.selected_ability()) {
if book.has_free_addon_slots() {
@ -67,7 +67,7 @@ impl Content<AbilityAddon> {
}
}
impl ContentUpdate for Content<AbilityAddon> {
impl<A: Ability + 'static> ContentUpdate for Content<A, AbilityAddon> {
fn update(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()> {
let reference = self.reference.clone();
@ -80,13 +80,15 @@ impl ContentUpdate for Content<AbilityAddon> {
move |controller_button| {
if let ControllerButton::X = controller_button {
CharacterWindow::salvage_from_inventory(&engine, hero, |inventory| {
inventory.remove_addon(index)
})?;
CharacterWindow::salvage_from_inventory::<A, _, _>(
&engine,
hero,
|inventory| inventory.remove_addon(index),
)?;
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let abilities = tabs.abilities();
let abilities = tabs.abilities::<A>();
abilities.update_page()?;
}
@ -145,19 +147,19 @@ impl ContentUpdate for Content<AbilityAddon> {
}
}
impl Content<AbilityBook> {
impl<A: Ability + 'static> Content<A, AbilityBook<A>> {
fn equip_book(
engine: &Arc<Engine>,
hero: Entity,
book_index: usize,
ability_page: &AbilityPage,
ability_page: &AbilityPage<A>,
) -> Result<()> {
engine.on_scene_mut(|scene| {
let entity = scene.entity_mut(hero)?;
let mut multi_mut = entity.multi_mut();
let inventory = multi_mut.get::<Inventory>()?;
let abilitiy_slots = multi_mut.get::<AbilitySlots>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
let abilitiy_slots = multi_mut.get::<AbilitySlots<A>>()?;
if let Some(old_book) = abilitiy_slots.insert_book(
inventory.remove_book(book_index),
@ -179,7 +181,7 @@ impl Content<AbilityBook> {
) -> Result<()> {
engine.on_scene(|scene| {
let entity = scene.entity(hero)?;
let inventory = entity.get_component::<Inventory>()?;
let inventory = entity.get_component::<Inventory<A>>()?;
let statistics = entity.get_component::<Statistics>()?;
let target_x = x + w as i32;
@ -191,9 +193,9 @@ impl Content<AbilityBook> {
gui.enable()?;
let window = reference.upgrade().unwrap();
let abilities = entity.get_component::<AbilitySlots>()?;
let abilities = entity.get_component::<AbilitySlots<A>>()?;
match abilities.book(window.tabs().abilities().right_side.selected_ability()) {
match abilities.book(window.tabs().abilities::<A>().right_side.selected_ability()) {
Some(selected_book) => {
let button_pos = gui.position_extent();
@ -222,7 +224,7 @@ impl Content<AbilityBook> {
}
}
impl ContentUpdate for Content<AbilityBook> {
impl<A: Ability + 'static> ContentUpdate for Content<A, AbilityBook<A>> {
fn update(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()> {
let reference = self.reference.clone();
@ -235,13 +237,15 @@ impl ContentUpdate for Content<AbilityBook> {
move |controller_button| {
if let ControllerButton::X = controller_button {
CharacterWindow::salvage_from_inventory(&engine, hero, |inventory| {
inventory.remove_book(index)
})?;
CharacterWindow::salvage_from_inventory::<A, _, _>(
&engine,
hero,
|inventory| inventory.remove_book(index),
)?;
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let abilities = tabs.abilities();
let abilities = tabs.abilities::<A>();
abilities.update_page()?;
}

View file

@ -16,7 +16,7 @@ use super::{
};
use crate::*;
pub struct AbilityPage {
pub struct AbilityPage<A: Ability + 'static> {
close: Weak<Button>,
engine: Arc<Engine>,
@ -31,10 +31,10 @@ pub struct AbilityPage {
current_mode: usize,
right_side: AbilityPageRightSide,
right_side: AbilityPageRightSide<A>,
}
impl AbilityPage {
impl<A: Ability + 'static> AbilityPage<A> {
pub fn new(
engine: &Arc<Engine>,
hero: Entity,
@ -65,7 +65,7 @@ impl AbilityPage {
engine.on_scene(|scene| {
let hero_object = scene.entity(hero)?;
let inventory = hero_object.get_component::<Inventory>()?;
let inventory = hero_object.get_component::<Inventory<A>>()?;
data = inventory.iter_books().cloned().collect();
@ -99,7 +99,7 @@ impl AbilityPage {
);
// addons
let addons_mode = PageContent::new(
let addons_mode = PageContent::<A, _>::new(
Content::new(&engine, reference.clone(), {
let engine = engine.clone();
let hero = hero.clone();
@ -109,7 +109,7 @@ impl AbilityPage {
engine.on_scene(|scene| {
let hero_object = scene.entity(hero)?;
let inventory = hero_object.get_component::<Inventory>()?;
let inventory = hero_object.get_component::<Inventory<A>>()?;
data = inventory.iter_addons().cloned().collect();
@ -192,7 +192,7 @@ impl AbilityPage {
move |index| {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let me = tabs.abilities();
let me = tabs.abilities::<A>();
if me.current_mode != index {
me.current_mode = index;
@ -223,7 +223,7 @@ impl AbilityPage {
}
}
impl Page for AbilityPage {
impl<A: Ability + 'static> Page for AbilityPage<A> {
fn enable(&mut self) -> Result<Arc<Grid>> {
println!("enable AbilityPage");

View file

@ -1,4 +1,7 @@
use std::sync::{Arc, Weak};
use std::{
marker::PhantomData,
sync::{Arc, Weak},
};
use crate::*;
@ -15,7 +18,7 @@ pub trait ContentUpdate {
fn select(&self) -> Result<()>;
}
pub struct Content<T: Send + Sync> {
pub struct Content<A: Ability + 'static, T: Send + Sync> {
pub reference: Weak<CharacterWindow>,
base: Arc<GuiSnippet>,
data: Vec<T>,
@ -24,9 +27,11 @@ pub struct Content<T: Send + Sync> {
page: usize,
pages: usize,
ability_marker: PhantomData<A>,
}
impl<T: Send + Sync> Content<T> {
impl<A: Ability + 'static, T: Send + Sync> Content<A, T> {
pub fn new<F>(
engine: &Arc<Engine>,
reference: Weak<CharacterWindow>,
@ -56,6 +61,8 @@ impl<T: Send + Sync> Content<T> {
page: 0,
pages: 1,
ability_marker: PhantomData,
})
}
@ -124,9 +131,9 @@ impl<T: Send + Sync> Content<T> {
}
}
impl<T: Send + Sync> ContentWrapper for Content<T>
impl<A: Ability + 'static, T: Send + Sync> ContentWrapper for Content<A, T>
where
Content<T>: ContentUpdate,
Content<A, T>: ContentUpdate,
{
fn refresh(&mut self) -> Result<()> {
self.data = (self.on_enable)()?;

View file

@ -17,9 +17,9 @@ use crate::{
use super::jewel_right_side::{LowerJewels, ReferenceItemSource, ReferenceObject};
impl Content<Item> {
impl<A: Ability + 'static> Content<A, Item> {
fn salvage_item(engine: &Arc<Engine>, hero: Entity, item_index: usize) -> Result<()> {
CharacterWindow::salvage_from_inventory(engine, hero, |inventory| {
CharacterWindow::salvage_from_inventory::<A, _, _>(engine, hero, |inventory| {
let mut item = inventory.remove_item(item_index);
// unsocket jewels and add them into inventory
@ -42,7 +42,7 @@ impl Content<Item> {
engine.on_scene_mut(|scene| {
let entity = scene.entity(hero)?;
let inventory = entity.get_component::<Inventory>()?;
let inventory = entity.get_component::<Inventory<A>>()?;
let item = inventory.item_at(item_index).clone();
if item.affixes.iter().any(|affix| {
@ -75,7 +75,7 @@ impl Content<Item> {
let mut multi_mut = entity.multi_mut();
let hero_items = multi_mut.get::<ItemSlotContainer>()?;
let inventory = multi_mut.get::<Inventory>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
let attributes = multi_mut.get::<Attributes>()?;
// remove item from inventory
@ -109,7 +109,7 @@ impl Content<Item> {
engine.on_scene(|scene| {
let entity = scene.entity(hero)?;
let inventory = entity.get_component::<Inventory>()?;
let inventory = entity.get_component::<Inventory<A>>()?;
let attributes = entity.get_component::<Attributes>()?;
let target_x = x + w as i32;
@ -155,7 +155,7 @@ impl Content<Item> {
}
}
impl ContentUpdate for Content<Item> {
impl<A: Ability + 'static> ContentUpdate for Content<A, Item> {
fn update(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()> {
let reference = self.reference.clone();
@ -173,7 +173,7 @@ impl ContentUpdate for Content<Item> {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
@ -185,7 +185,7 @@ impl ContentUpdate for Content<Item> {
if Self::select_to_socket(&engine, hero, index)? {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.switch_to_jewels()?;
}
@ -208,7 +208,7 @@ impl ContentUpdate for Content<Item> {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
@ -247,7 +247,7 @@ impl ContentUpdate for Content<Item> {
}
}
impl Content<Jewel> {
impl<A: Ability + 'static> Content<A, Jewel> {
fn show_jewel_tooltip(
engine: &Arc<Engine>,
hero: Entity,
@ -257,7 +257,7 @@ impl Content<Jewel> {
) -> Result<()> {
engine.on_scene(|scene| {
let entity = scene.entity(hero)?;
let inventory = entity.get_component::<Inventory>()?;
let inventory = entity.get_component::<Inventory<A>>()?;
let target_x = x + w as i32;
let target_y = y;
@ -285,7 +285,7 @@ impl Content<Jewel> {
fn select_to_combine(engine: &Arc<Engine>, hero: Entity, jewel_index: usize) -> Result<()> {
engine.on_scene_mut(|scene| {
let entity = scene.entity(hero)?;
let inventory = entity.get_component::<Inventory>()?;
let inventory = entity.get_component::<Inventory<A>>()?;
let jewel = inventory.jewel_at(jewel_index).clone();
// add to reference
@ -312,7 +312,7 @@ impl Content<Jewel> {
fn select_to_lower(engine: &Arc<Engine>, hero: Entity, jewel_index: usize) -> Result<()> {
engine.on_scene_mut(|scene| {
let entity = scene.entity(hero)?;
let inventory = entity.get_component::<Inventory>()?;
let inventory = entity.get_component::<Inventory<A>>()?;
let jewel = inventory.jewel_at(jewel_index).clone();
// remove from reference if placed there
@ -342,7 +342,7 @@ impl Content<Jewel> {
}
}
impl ContentUpdate for Content<Jewel> {
impl<A: Ability + 'static> ContentUpdate for Content<A, Jewel> {
fn update(&mut self, engine: &Arc<Engine>, hero: Entity) -> Result<()> {
let reference = self.reference.clone();
@ -378,7 +378,7 @@ impl ContentUpdate for Content<Jewel> {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
@ -398,7 +398,7 @@ impl ContentUpdate for Content<Jewel> {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
@ -420,7 +420,7 @@ impl ContentUpdate for Content<Jewel> {
}
}
impl ContentUpdate for Content<MapItem> {
impl<A: Ability + 'static> ContentUpdate for Content<A, MapItem> {
fn update(&mut self, engine: &Arc<Engine>, _hero: Entity) -> Result<()> {
self.update_base(engine, |_button, _t, _index| {
// button.set_icon(&t.icon)?;

View file

@ -23,7 +23,7 @@ pub struct ItemRightSide {
}
impl ItemRightSide {
pub fn new(
pub fn new<A: Ability + 'static>(
engine: &Arc<Engine>,
file: &str,
reference: &Weak<CharacterWindow>,
@ -37,12 +37,12 @@ impl ItemRightSide {
empty_icons: icons,
};
me.setup(engine, reference, hero)?;
me.setup::<A>(engine, reference, hero)?;
Ok(me)
}
fn setup(
fn setup<A: Ability + 'static>(
&self,
engine: &Arc<Engine>,
reference: &Weak<CharacterWindow>,
@ -253,7 +253,7 @@ mod macros {
let mut multi_mut = entity.multi_mut();
let items = multi_mut.get::<ItemSlotContainer>()?;
let inventory = multi_mut.get::<Inventory>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
if let Some($item) = items.[<$item>]() {
inventory.add_item($item.clone());
@ -285,7 +285,7 @@ mod macros {
if found_item {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
@ -333,7 +333,7 @@ mod macros {
if empty_affixes_found {
let window = reference.upgrade().unwrap();
let mut tabs = window.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.switch_to_jewels()?;
}
@ -405,7 +405,7 @@ mod macros {
let mut multi_mut = entity.multi_mut();
let items = multi_mut.get::<ItemSlotContainer>()?;
let inventory = multi_mut.get::<Inventory>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
if let Some($item) = items.[<$item>]($index) {
inventory.add_item($item.clone());
@ -437,7 +437,7 @@ mod macros {
if found_item {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
@ -485,7 +485,7 @@ mod macros {
if empty_affixes_found {
let window = reference.upgrade().unwrap();
let mut tabs = window.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.switch_to_jewels()?;
}

View file

@ -46,7 +46,7 @@ pub struct JewelRightSide {
}
impl JewelRightSide {
pub fn new(
pub fn new<A: Ability + 'static>(
engine: &Arc<Engine>,
file: &str,
hero: Entity,
@ -67,12 +67,12 @@ impl JewelRightSide {
})?;
let me = Self { snippet };
me.setup_select(engine, hero, reference)?;
me.setup_select::<A>(engine, hero, reference)?;
Ok(me)
}
fn setup_select(
fn setup_select<A: Ability + 'static>(
&self,
engine: &Arc<Engine>,
hero: Entity,
@ -180,7 +180,7 @@ impl JewelRightSide {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let inventory = tabs.inventory();
let inventory = tabs.inventory::<A>();
inventory.update_page(true)?;
}
@ -219,7 +219,7 @@ impl JewelRightSide {
.for_each(|j| *j = None);
}
pub fn combine(engine: &Arc<Engine>, hero: Entity) -> Result<bool> {
pub fn combine<A: Ability + 'static>(engine: &Arc<Engine>, hero: Entity) -> Result<bool> {
let scene = engine.scene_mut();
let (resources, entity) = scene.entity_resource(hero)?;
@ -244,7 +244,7 @@ impl JewelRightSide {
match source {
ReferenceItemSource::Inventory(index) => {
let inventory = entity.get_component_mut::<Inventory>()?;
let inventory = entity.get_component_mut::<Inventory<A>>()?;
let item = inventory.item_mut_at(*index);
@ -276,7 +276,7 @@ impl JewelRightSide {
let mut multi_mut = entity.multi_mut();
let inventory = multi_mut.get::<Inventory>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
let item_slots = multi_mut.get::<ItemSlotContainer>()?;
let slot = item.slot;
@ -328,9 +328,9 @@ impl JewelRightSide {
}
let item_settings = resources.get::<ItemSettings>();
let item_system = resources.get::<ItemSystem>();
let item_system = resources.get::<ItemSystem<A>>();
let inventory = entity.get_component_mut::<Inventory>()?;
let inventory = entity.get_component_mut::<Inventory<A>>()?;
let upper_jewel = inventory.jewel_mut_at(*index);

View file

@ -3,11 +3,13 @@ mod item_right_side;
mod jewel_right_side;
mod map_right_side;
use std::marker::PhantomData;
use std::sync::{Arc, Weak};
use anyhow::Result;
use engine::prelude::*;
use rpg_components::components::inventory::Inventory;
use rpg_components::items::ability_book::Ability;
use super::page_content::PageContent;
use super::traits::*;
@ -16,7 +18,7 @@ use item_right_side::ItemRightSide;
use jewel_right_side::JewelRightSide;
use map_right_side::MapRightSide;
pub struct InventoryPage {
pub struct InventoryPage<A: Ability + 'static> {
close: Weak<Button>,
engine: Arc<Engine>,
@ -30,9 +32,11 @@ pub struct InventoryPage {
modes: [Box<dyn PageContentWrapper>; 3],
current_mode: usize,
ability_marker: PhantomData<A>,
}
impl InventoryPage {
impl<A: Ability + 'static> InventoryPage<A> {
pub fn new(
engine: &Arc<Engine>,
hero: Entity,
@ -53,7 +57,7 @@ impl InventoryPage {
let content = left_base.element("content")?;
// items
let item_mode = PageContent::new(
let item_mode = PageContent::<A, _>::new(
Content::new(engine, reference.clone(), {
let engine = engine.clone();
let hero = hero.clone();
@ -63,7 +67,7 @@ impl InventoryPage {
engine.on_scene(|scene| {
let hero_object = scene.entity(hero)?;
let inventory = hero_object.get_component::<Inventory>()?;
let inventory = hero_object.get_component::<Inventory<A>>()?;
data = inventory.iter_items().cloned().collect();
@ -93,7 +97,7 @@ impl InventoryPage {
ui
},
ItemRightSide::new(
ItemRightSide::new::<A>(
engine,
include_str!("../../resources/inventory/items/right_side.xml"),
&reference,
@ -102,7 +106,7 @@ impl InventoryPage {
);
// jewels
let jewel_mode = PageContent::new(
let jewel_mode = PageContent::<A, _>::new(
Content::new(engine, reference.clone(), {
let engine = engine.clone();
let hero = hero.clone();
@ -112,7 +116,7 @@ impl InventoryPage {
engine.on_scene(|scene| {
let hero_object = scene.entity(hero)?;
let inventory = hero_object.get_component::<Inventory>()?;
let inventory = hero_object.get_component::<Inventory<A>>()?;
data = inventory.iter_jewels().cloned().collect();
@ -139,7 +143,7 @@ impl InventoryPage {
ui
},
JewelRightSide::new(
JewelRightSide::new::<A>(
engine,
include_str!("../../resources/inventory/jewels/right_side.xml"),
hero,
@ -148,7 +152,7 @@ impl InventoryPage {
);
// maps
let map_mode = PageContent::new(
let map_mode = PageContent::<A, _>::new(
Content::new(engine, reference.clone(), {
let engine = engine.clone();
let hero: Entity = hero.clone();
@ -158,7 +162,7 @@ impl InventoryPage {
engine.on_scene(|scene| {
let hero_object = scene.entity(hero)?;
let inventory = hero_object.get_component::<Inventory>()?;
let inventory = hero_object.get_component::<Inventory<A>>()?;
data = inventory.iter_maps().cloned().collect();
@ -209,6 +213,8 @@ impl InventoryPage {
],
current_mode: 0,
ability_marker: PhantomData,
})
}
@ -315,7 +321,7 @@ impl InventoryPage {
move |index| {
if let Some(menu) = reference.upgrade() {
let mut tabs = menu.tabs_mut();
let me = tabs.inventory();
let me = tabs.inventory::<A>();
if me.current_mode != index {
me.current_mode = index;
@ -353,7 +359,7 @@ impl InventoryPage {
}
}
impl Page for InventoryPage {
impl<A: Ability + 'static> Page for InventoryPage<A> {
fn enable(&mut self) -> Result<Arc<Grid>> {
println!("enable InventoryPage");
@ -423,7 +429,7 @@ impl Page for InventoryPage {
ControllerButton::RightStick => {
// check if jewel page is open
if self.current_mode == 1 {
if JewelRightSide::combine(&self.engine, self.hero)? {
if JewelRightSide::combine::<A>(&self.engine, self.hero)? {
JewelRightSide::clear(&self.engine);
self.update_page(true)?;
}

View file

@ -7,9 +7,12 @@ mod traits;
use anyhow::Result;
use engine::prelude::*;
use rpg_components::components::{
use rpg_components::{
components::{
crafting_materials::CraftingMaterials,
inventory::{Inventory, Storable},
},
items::ability_book::Ability,
};
use std::{
@ -76,11 +79,11 @@ impl<'a> Tabs<'a> {
Self::downcast_unchecked(&self.tabs[0])
}
pub fn inventory(&mut self) -> &'a InventoryPage {
pub fn inventory<A: Ability + 'static>(&mut self) -> &'a InventoryPage<A> {
Self::downcast_unchecked(&self.tabs[1])
}
pub fn abilities(&mut self) -> &'a AbilityPage {
pub fn abilities<A: Ability + 'static>(&mut self) -> &'a AbilityPage<A> {
Self::downcast_unchecked(&self.tabs[2])
}
@ -104,11 +107,11 @@ impl<'a> TabsMut<'a> {
Self::downcast_mut_unchecked(&mut self.tabs[0])
}
pub fn inventory(&mut self) -> &'a mut InventoryPage {
pub fn inventory<A: Ability + 'static>(&mut self) -> &'a mut InventoryPage<A> {
Self::downcast_mut_unchecked(&mut self.tabs[1])
}
pub fn abilities(&mut self) -> &'a mut AbilityPage {
pub fn abilities<A: Ability + 'static>(&mut self) -> &'a mut AbilityPage<A> {
Self::downcast_mut_unchecked(&mut self.tabs[2])
}
@ -137,7 +140,7 @@ pub struct CharacterWindow {
}
impl CharacterWindow {
pub fn new(
pub fn new<A: Ability + 'static>(
engine: Arc<Engine>,
hero: Entity,
name: &str,
@ -162,8 +165,10 @@ impl CharacterWindow {
tabs: RwLock::new([
Box::new(CharacterPage::new(&engine, hero, name, me).unwrap()),
Box::new(InventoryPage::new(&engine, hero, me.clone(), &close_button).unwrap()),
Box::new(AbilityPage::new(&engine, hero, me.clone(), &close_button).unwrap()),
Box::new(
InventoryPage::<A>::new(&engine, hero, me.clone(), &close_button).unwrap(),
),
Box::new(AbilityPage::<A>::new(&engine, hero, me.clone(), &close_button).unwrap()),
]),
tab: AtomicUsize::new(0),
@ -250,9 +255,10 @@ impl CharacterWindow {
self.tooltips.lock().unwrap().remove(&name.to_string());
}
pub fn salvage_from_inventory<F, S>(engine: &Engine, hero: Entity, f: F) -> Result<()>
pub fn salvage_from_inventory<A, F, S>(engine: &Engine, hero: Entity, f: F) -> Result<()>
where
F: FnOnce(&mut Inventory) -> S,
A: Ability + 'static,
F: FnOnce(&mut Inventory<A>) -> S,
S: Storable,
{
engine.on_scene_mut(|scene| {
@ -261,7 +267,7 @@ impl CharacterWindow {
let mut multi_mut = entity.multi_mut();
let crafting_materials = multi_mut.get::<CraftingMaterials>()?;
let inventory = multi_mut.get::<Inventory>()?;
let inventory = multi_mut.get::<Inventory<A>>()?;
// remove callback
let storable = f(inventory);

View file

@ -17,15 +17,15 @@ impl RightSide for EmptyRightSide {
}
}
pub struct PageContent<T: Send + Sync> {
content: Content<T>,
pub struct PageContent<A: Ability + 'static, T: Send + Sync> {
content: Content<A, T>,
tooltip: Arc<GuiSnippet>,
right_side: Box<dyn RightSide>,
}
impl<T: Send + Sync> PageContent<T> {
pub fn new<R>(content: Content<T>, tooltip: Arc<GuiSnippet>, right_side: R) -> Self
impl<A: Ability + 'static, T: Send + Sync> PageContent<A, T> {
pub fn new<R>(content: Content<A, T>, tooltip: Arc<GuiSnippet>, right_side: R) -> Self
where
R: RightSide + 'static,
{
@ -37,9 +37,9 @@ impl<T: Send + Sync> PageContent<T> {
}
}
impl<T: Send + Sync> PageContentWrapper for PageContent<T>
impl<A: Ability + 'static, T: Send + Sync> PageContentWrapper for PageContent<A, T>
where
Content<T>: ContentUpdate,
Content<A, T>: ContentUpdate,
{
fn content(&self) -> &dyn ContentWrapper {
&self.content

View file

@ -5,14 +5,6 @@ use engine::prelude::*;
use cgmath::Vector3;
use std::path::Path;
use crate::{
ability_type::AbilityType,
damage_type::DamageType,
items::{ability_addon::AbilityAddonCollection, ability_book::Ability},
};
use super::statistics::Statistics;
const ABILITY_SUFFIX: &str = ".abil";
create_settings_section!(

View file

@ -1,4 +1,5 @@
mod ability_location_info;
pub mod abilityloader;
pub mod ai;
mod aoe;
pub mod aoe_arc;

View file

@ -2,5 +2,6 @@ pub mod abilities;
pub mod components;
pub mod objects;
pub mod ability_type;
pub mod lightning;
pub mod prelude;

View file

@ -1,4 +1,5 @@
pub use super::abilities::prelude::*;
pub use super::ability_type::AbilityType;
pub use super::components::*;
pub use super::lightning::{Lightning, LightningMarker};
pub use super::objects::hero::{Hero, MainUser};

View file

@ -8,9 +8,9 @@ use std::{
str::FromStr,
};
use crate::config::save_game::SaveGame;
use crate::items::{ability_addon::AbilityAddonTypes, ability_book::AbilityBook, Rarities};
use crate::{components::inventory::Storable, items::ItemSystem};
use crate::{config::save_game::SaveGame, items::ability_book::Ability};
macro_rules! load {
($me: ident, $item_system:ident, $save_game:ident, $($index:literal,)+) => {
@ -67,16 +67,16 @@ macro_rules! store {
};
}
pub struct AbilitySlots {
pub direction: Vector2<f32>,
abilities: [Option<AbilityBook>; AbilitySlots::MAX_ABILITIES],
}
impl AbilitySlots {
// stupid workaround for serde Deserialize
pub const MAX_ABILITIES: usize = 4;
pub struct AbilitySlots<A: Ability> {
pub direction: Vector2<f32>,
abilities: [Option<AbilityBook<A>>; MAX_ABILITIES],
}
impl<A: Ability> AbilitySlots<A> {
pub fn empty() -> Self {
Self {
direction: Vector2::zero(),
@ -84,7 +84,7 @@ impl AbilitySlots {
}
}
pub fn load(item_system: &ItemSystem, save_game: &SaveGame) -> Result<Self> {
pub fn load(item_system: &ItemSystem<A>, save_game: &SaveGame) -> Result<Self> {
let mut me = Self::empty();
load!(me, item_system, save_game, 0, 1, 2, 3,);
@ -96,7 +96,7 @@ impl AbilitySlots {
store!(self, save_game, 0, 1, 2, 3,);
}
pub fn insert_book(&mut self, book: AbilityBook, index: usize) -> Option<AbilityBook> {
pub fn insert_book(&mut self, book: AbilityBook<A>, index: usize) -> Option<AbilityBook<A>> {
match self.abilities[index].clone() {
Some(ability) => {
if ability != book {
@ -119,30 +119,30 @@ impl AbilitySlots {
// self.abilities[index] = None;
// }
pub fn book(&self, index: usize) -> Option<&AbilityBook> {
pub fn book(&self, index: usize) -> Option<&AbilityBook<A>> {
self.abilities[index].as_ref()
}
pub fn book_mut(&mut self, index: usize) -> Option<&mut AbilityBook> {
pub fn book_mut(&mut self, index: usize) -> Option<&mut AbilityBook<A>> {
self.abilities[index].as_mut()
}
pub fn iter(&self) -> Iter<'_, Option<AbilityBook>> {
pub fn iter(&self) -> Iter<'_, Option<AbilityBook<A>>> {
self.abilities.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, Option<AbilityBook>> {
pub fn iter_mut(&mut self) -> IterMut<'_, Option<AbilityBook<A>>> {
self.abilities.iter_mut()
}
}
impl EntityComponent for AbilitySlots {
impl<A: Ability + 'static> EntityComponent for AbilitySlots<A> {
fn name(&self) -> &str {
Self::debug_name()
}
}
impl ComponentDebug for AbilitySlots {
impl<A: Ability> ComponentDebug for AbilitySlots<A> {
fn debug_name() -> &'static str {
"AbilitySlots"
}

View file

@ -5,7 +5,7 @@ use std::{cmp::Ordering, slice::Iter, str::FromStr};
use crate::{
config::attributes::{AttributeColorSettings, StartingAttributes},
items::ItemSystem,
items::{ability_book::Ability, ItemSystem},
};
generate_stat!(Agility, u32, "Agility");
@ -37,12 +37,12 @@ impl Attribute {
ATTRIBUTES.iter()
}
pub fn apply_color(
pub fn apply_color<A: Ability>(
&self,
base_image: &RgbaImage,
color_settins: &AttributeColorSettings,
) -> RgbaImage {
ItemSystem::apply_color(base_image, color_settins.from_attribute(*self))
ItemSystem::<A>::apply_color(base_image, color_settins.from_attribute(*self))
}
}

View file

@ -6,8 +6,9 @@ use std::sync::Arc;
use crate::{
config::save_game::SaveGame,
items::{
ability_addon::AbilityAddon, ability_book::AbilityBook, Item, ItemSystem, Jewel, MapItem,
Rarities,
ability_addon::AbilityAddon,
ability_book::{Ability, AbilityBook},
Item, ItemSystem, Jewel, MapItem, Rarities,
},
};
@ -17,15 +18,15 @@ pub trait Storable {
}
#[derive(Default, Clone)]
pub struct Inventory {
pub struct Inventory<A: Ability> {
items: Vec<Item>,
addons: Vec<AbilityAddon>,
books: Vec<AbilityBook>,
books: Vec<AbilityBook<A>>,
jewels: Vec<Jewel>,
maps: Vec<MapItem>,
}
impl Inventory {
impl<A: Ability> Inventory<A> {
// ------- items --------
pub fn add_item(&mut self, item: Item) {
self.items.push(item);
@ -123,30 +124,30 @@ impl Inventory {
}
// ------- books --------
pub fn add_book(&mut self, book: AbilityBook) {
pub fn add_book(&mut self, book: AbilityBook<A>) {
self.books.push(book);
}
pub fn insert_book(&mut self, book: AbilityBook, index: usize) {
pub fn insert_book(&mut self, book: AbilityBook<A>, index: usize) {
self.books.insert(index, book);
}
pub fn remove_book(&mut self, index: usize) -> AbilityBook {
pub fn remove_book(&mut self, index: usize) -> AbilityBook<A> {
self.books.remove(index)
}
pub fn iter_books(&self) -> Iter<'_, AbilityBook> {
pub fn iter_books(&self) -> Iter<'_, AbilityBook<A>> {
self.books.iter()
}
pub fn book_at(&self, index: usize) -> &AbilityBook {
pub fn book_at(&self, index: usize) -> &AbilityBook<A> {
&self.books[index]
}
}
impl Inventory {
pub fn load(save_game: &SaveGame, item_system: &ItemSystem) -> Result<Self> {
let mut inventory = Inventory::default();
impl<A: Ability> Inventory<A> {
pub fn load(save_game: &SaveGame, item_system: &ItemSystem<A>) -> Result<Self> {
let mut inventory: Inventory<A> = Default::default();
for item_string in save_game.inventory.items.iter() {
if !item_string.is_empty() {
@ -219,13 +220,13 @@ impl Inventory {
}
}
impl EntityComponent for Inventory {
impl<A: Ability + 'static> EntityComponent for Inventory<A> {
fn name(&self) -> &str {
Self::debug_name()
}
}
impl ComponentDebug for Inventory {
impl<A: Ability> ComponentDebug for Inventory<A> {
fn debug_name() -> &'static str {
"Inventory"
}

View file

@ -6,7 +6,7 @@ use std::collections::HashMap;
use crate::{
config::{items::ItemSettings, save_game::SaveGame},
items::{Item, ItemAffix, ItemSlots, ItemSystem, Rarities},
items::{ability_book::Ability, Item, ItemAffix, ItemSlots, ItemSystem, Rarities},
};
use super::{
@ -177,7 +177,7 @@ impl ItemSlotContainer {
}
}
pub fn load(save_game: &SaveGame, item_system: &ItemSystem) -> Result<Self> {
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);

View file

@ -2,7 +2,6 @@
pub mod macros;
pub mod ability_slots;
pub mod abilityloader;
pub mod attributes;
pub mod character_status;
pub mod crafting_materials;

View file

@ -7,7 +7,7 @@ use crate::{
crafting_materials::CraftingMaterials, inventory::Inventory, item_slots::ItemSlotContainer,
level::Level, statistics::Statistics,
},
items::{ItemAffix, ItemSystem, Rarities},
items::{ability_book::Ability, ItemAffix, ItemSystem, Rarities},
};
use std::env::var;
@ -359,13 +359,16 @@ create_settings_container!(
);
impl SaveGame {
pub fn to_entity_object(self, engine: &Engine) -> Result<(Entity, String)> {
pub fn to_entity_object<A: Ability + 'static>(
self,
engine: &Engine,
) -> Result<(Entity, String)> {
let scene = engine.scene_mut();
let experience_settings = scene.resources.get::<ExperienceSettings>();
let attribute_settings = scene.resources.get::<AttributeSettings>();
let item_settings = scene.resources.get::<ItemSettings>();
let item_system = scene.resources.get::<ItemSystem>();
let item_system = scene.resources.get::<ItemSystem<A>>();
let mut entity_object = engine.assets().empty_entity();

View file

@ -12,11 +12,9 @@ use std::{
use std::sync::Arc;
use crate::{
ability_type::AbilityType, components::inventory::Storable, config::abilities::AbilitySettings,
};
use crate::{components::inventory::Storable, config::abilities::AbilitySettings};
use super::{ItemSystem, Rarities, Tooltip};
use super::{ability_book::Ability, ItemSystem, Rarities, Tooltip};
const COOL_DOWN_REDUCTION_CAP: f32 = 0.7;
@ -102,32 +100,6 @@ impl AbilityAddonTypes {
}
}
pub fn is_allowed_for(&self, ability_type: AbilityType) -> bool {
match ability_type {
AbilityType::SelfCast => match self {
Self::Damage(_) => true,
Self::ProjectileSpeed(_) => false,
Self::Bounce => false,
Self::Explosion(_) => false,
Self::Size(_) => true,
Self::Projectiles(_) => false,
Self::CoolDown(_) => true,
Self::Distance(_) => false,
},
AbilityType::Projectile => match self {
Self::Damage(_) => true,
Self::ProjectileSpeed(_) => true,
Self::Bounce => true,
Self::Explosion(_) => true,
Self::Size(_) => true,
Self::Projectiles(_) => true,
Self::CoolDown(_) => true,
Self::Distance(_) => true,
},
}
}
pub fn into_zero(self) -> Self {
match self {
AbilityAddonTypes::Damage(_) => AbilityAddonTypes::Damage(0),
@ -262,9 +234,9 @@ impl AbilityAddon {
format!("{}|{}", self.addon_type(), self.rarity())
}
pub fn from_persistent<'a>(
pub fn from_persistent<'a, A: Ability>(
mut split: impl Iterator<Item = &'a str>,
item_system: &ItemSystem,
item_system: &ItemSystem<A>,
) -> Result<Self> {
let addon_type = AbilityAddonTypes::from_str(split.next().unwrap())?;
let rarity = Rarities::from_str(split.next().unwrap())?;

View file

@ -1,4 +1,5 @@
use anyhow::Result;
use assetpath::AssetPath;
use cgmath::{Vector2, Vector3};
use engine::prelude::*;
@ -6,10 +7,11 @@ use std::{fmt::Debug, str::FromStr, sync::Arc, time::Duration};
use crate::{
components::{
abilityloader::AbilityLoader, character_status::CharacterStatus,
crafting_materials::CraftingMaterials, inventory::Storable, statistics::Statistics,
character_status::CharacterStatus, crafting_materials::CraftingMaterials,
inventory::Storable, statistics::Statistics,
},
config::abilities::{AbilityLevel, AbilitySettings},
damage_type::DamageType,
};
use super::{
@ -17,19 +19,17 @@ use super::{
ItemSystem, Rarities, Tooltip,
};
#[derive(Debug, Clone)]
pub struct Ability {
pub(crate) data: AbilityLoader,
}
pub trait Ability: Send + Sync + Clone + Default {
fn create(asset_path: impl Into<AssetPath>) -> Result<Self>;
impl Ability {
pub fn data(&self) -> &AbilityLoader {
&self.data
}
fn name(&self) -> &str;
fn icon_path(&self) -> &AssetPath;
pub fn name(&self) -> &str {
self.data.name()
}
fn cool_down(&self) -> Duration;
fn mana_cost(&self) -> u32;
fn mana_cost_per_level(&self) -> u32;
fn damage_type(&self) -> DamageType;
fn damage(&self, level: u32, addons: &AbilityAddonCollection, statistics: &Statistics) -> u32;
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -40,8 +40,8 @@ pub struct CastInformation {
}
#[derive(Clone)]
pub struct AbilityBook {
ability: Ability,
pub struct AbilityBook<A: Ability> {
ability: A,
// meta
icon: Arc<Image>,
@ -57,9 +57,9 @@ pub struct AbilityBook {
last_cast: Option<CastInformation>,
}
impl AbilityBook {
impl<A: Ability> AbilityBook<A> {
pub fn new(
ability: Ability,
ability: A,
icon: Arc<Image>,
rarity: Rarities,
ability_settings: &AbilitySettings,
@ -83,7 +83,7 @@ impl AbilityBook {
}
pub fn load(
ability: Ability,
ability: A,
icon: Arc<Image>,
rarity: Rarities,
addons: Vec<Option<AbilityAddon>>,
@ -122,7 +122,7 @@ impl AbilityBook {
if let Some(cast_information) = &self.last_cast {
let total_cool_down = Duration::from_secs_f32({
let d: Duration = self.ability.data().settings.parameter.cool_down.into();
let d = self.ability.cool_down();
d.as_secs_f32() * (1.0 - self.addons.cool_down_reduction())
});
@ -174,12 +174,7 @@ impl AbilityBook {
match &self.last_cast {
Some(cast_information) => {
let total_cool_down = Duration::from_secs_f32(
self.ability
.data()
.settings
.parameter
.cool_down
.as_secs_f32()
self.ability.cool_down().as_secs_f32()
* (1.0 - self.addons.cool_down_reduction()),
);
@ -197,7 +192,7 @@ impl AbilityBook {
}
}
pub fn ability(&self) -> &Ability {
pub fn ability(&self) -> &A {
&self.ability
}
@ -242,10 +237,7 @@ impl AbilityBook {
}
pub fn mana_cost(&self) -> u32 {
let data = self.ability.data();
data.settings.parameter.base_mana_cost
+ data.settings.parameter.mana_cost_per_level * (self.level - 1)
self.ability.mana_cost() + self.ability.mana_cost_per_level() * (self.level - 1)
}
pub fn into_persistent(&self) -> String {
@ -260,7 +252,7 @@ impl AbilityBook {
pub fn from_persistent<'a>(
mut split: impl Iterator<Item = &'a str>,
item_system: &ItemSystem,
item_system: &ItemSystem<A>,
) -> Result<Self> {
let name = split.next().unwrap();
let rarity = Rarities::from_str(split.next().unwrap())?;
@ -315,22 +307,19 @@ impl AbilityBook {
let damage: Arc<Label> = gui.element("damage")?;
let cooldown: Arc<Label> = gui.element("cooldown")?;
let data = self.ability().data();
mana_costs.set_text(self.mana_cost())?;
damage.set_text(data.damage(self.level(), self.addons(), statistics))?;
damage.set_text_color(data.settings.parameter.damage_type.into())?;
damage.set_text(self.ability.damage(self.level(), self.addons(), statistics))?;
damage.set_text_color(self.ability.damage_type().into())?;
cooldown.set_text(format!(
"{:.1} s",
data.settings.parameter.cool_down.as_secs_f32()
* (1.0 - self.addons().cool_down_reduction())
self.ability.cool_down().as_secs_f32() * (1.0 - self.addons().cool_down_reduction())
))?;
Ok(Tooltip::new(inspector_grid, gui, gui_handler.clone()))
}
}
impl Debug for AbilityBook {
impl<A: Ability> Debug for AbilityBook<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AbilityBook")
.field("rarity", &self.rarity)
@ -341,16 +330,16 @@ impl Debug for AbilityBook {
}
}
impl PartialEq for AbilityBook {
impl<A: Ability> PartialEq for AbilityBook<A> {
fn eq(&self, other: &Self) -> bool {
self.ability.data() == other.ability.data()
self.ability.name() == other.ability.name()
&& self.rarity == other.rarity
&& self.addons == other.addons
&& self.level == other.level
}
}
impl Storable for AbilityBook {
impl<A: Ability> Storable for AbilityBook<A> {
fn rarity(&self) -> Rarities {
self.rarity
}

View file

@ -16,7 +16,7 @@ use crate::{
config::items::ItemSettings,
};
use super::{ItemSlots, ItemSystem, Jewel, Rarities, Tooltip};
use super::{ability_book::Ability, ItemSlots, ItemSystem, Jewel, Rarities, Tooltip};
const ITEM_SNIPPETS: [&'static str; 8] = [
include_str!("../../resources/items/slots_0.xml"),
@ -155,9 +155,9 @@ impl Item {
base
}
pub fn from_persistent<'a>(
pub fn from_persistent<'a, A: Ability>(
mut split: impl Iterator<Item = &'a str>,
item_system: &ItemSystem,
item_system: &ItemSystem<A>,
) -> Result<Self> {
let slot = ItemSlots::from_str(split.next().unwrap())?;
let rarity = Rarities::from_str(split.next().unwrap())?;

View file

@ -7,7 +7,6 @@ use std::sync::{Arc, Mutex};
use image::{imageops::FilterType, DynamicImage, ImageBuffer, Pixel, Rgba, RgbaImage};
use crate::components::abilityloader::AbilityLoader;
use crate::components::attributes::{Attribute, Attributes};
use crate::components::inventory::Storable;
use crate::components::statistic_types::{
@ -22,14 +21,14 @@ use super::ability_book::{Ability, AbilityBook};
use super::{Item, ItemAffix, ItemSlots, Jewel, Rarities};
#[derive(Debug, Clone, PartialEq)]
pub enum Loot {
pub enum Loot<A: Ability> {
Item(Item),
AbilityBook(AbilityBook),
AbilityBook(AbilityBook<A>),
AbilityAddOn(AbilityAddon),
Jewel(Jewel),
}
impl Loot {
impl<A: Ability> Loot<A> {
pub fn storable(&self) -> &dyn Storable {
match self {
Loot::Item(item) => item,
@ -40,7 +39,7 @@ impl Loot {
}
}
pub struct ItemSystem {
pub struct ItemSystem<A: Ability> {
pub item_settings: ItemSettings,
ability_settings: AbilitySettings,
@ -49,25 +48,24 @@ pub struct ItemSystem {
addon_icon_combinations: HashMap<(Rarities, AbilityAddonTypes), Arc<Image>>,
jewel_icon_combinations: HashMap<(Rarities, u32, Attribute), Arc<Image>>,
abilities: Vec<Ability>,
abilities: Vec<A>,
}
impl ItemSystem {
impl<A: Ability> ItemSystem<A> {
pub fn new(
engine: &Arc<Engine>,
item_settings: &ItemSettings,
ability_settings: &AbilitySettings,
attribute_settings: &AttributeSettings,
ability_directory: &AssetPath,
data_directory: &str,
) -> Result<Self> {
// verify that drop chances sum up to 1.0
item_settings.rarity_drop_rates.verify();
let ability_loader = AbilityLoader::list_all_ability_files(ability_directory)?
let abilities = search_dir_recursively(&ability_directory.full_path(), ".abil")?
.into_iter()
.map(|path| AbilityLoader::load(data_directory, path))
.collect::<Result<Vec<AbilityLoader>>>()?;
.map(|path| A::create(path))
.collect::<Result<Vec<A>>>()?;
let (
item_icon_combinations,
@ -89,8 +87,8 @@ impl ItemSystem {
// image for ability book
let mut ability_images = Vec::new();
for loader in ability_loader.iter() {
let path = &loader.settings.meta.icon;
for loader in abilities.iter() {
let path = loader.icon_path();
if !path.is_empty() {
ability_images.push((loader.name().to_string(), Self::dyn_image(path)?));
@ -140,7 +138,10 @@ impl ItemSystem {
for rarity in Rarities::iter() {
let final_image = Self::blend_background(
icon,
&rarity.apply_color(&base_background, &item_settings.rarity_color_settings),
&rarity.apply_color::<A>(
&base_background,
&item_settings.rarity_color_settings,
),
);
let (width, height) = final_image.dimensions();
@ -165,7 +166,10 @@ impl ItemSystem {
for rarity in Rarities::iter() {
let final_image = Self::blend_background(
&image,
&rarity.apply_color(&base_background, &item_settings.rarity_color_settings),
&rarity.apply_color::<A>(
&base_background,
&item_settings.rarity_color_settings,
),
);
let (width, height) = final_image.dimensions();
@ -189,8 +193,10 @@ impl ItemSystem {
for (addon_type, icon) in ability_addon_icons.iter() {
for rarity in Rarities::iter() {
let final_image = Self::blend_apply(
&rarity
.apply_color(&addon_background, &item_settings.rarity_color_settings),
&rarity.apply_color::<A>(
&addon_background,
&item_settings.rarity_color_settings,
),
icon,
|rarity_color, icon_color| {
// let (r1, g1, b1, a1) = rarity_color.channels4();
@ -224,13 +230,13 @@ impl ItemSystem {
for (level, icon) in jewel_icons.iter() {
for attribute in Attribute::iter() {
let attribute_icon =
attribute.apply_color(&icon, &attribute_settings.attribute_color_settings);
let attribute_icon = attribute
.apply_color::<A>(&icon, &attribute_settings.attribute_color_settings);
for rarity in Rarities::iter() {
let final_image = Self::blend_background(
&attribute_icon,
&rarity.apply_color(
&rarity.apply_color::<A>(
&base_background,
&item_settings.rarity_color_settings,
),
@ -260,11 +266,6 @@ impl ItemSystem {
)
};
let abilities = ability_loader
.into_iter()
.map(|loader| loader.create_ability())
.collect::<Vec<Ability>>();
Ok(ItemSystem {
item_settings: item_settings.clone(),
ability_settings: ability_settings.clone(),
@ -293,7 +294,7 @@ impl ItemSystem {
}
/// only here for debugging
pub fn get_legendary_random_loot(&self, level: u32) -> Loot {
pub fn get_legendary_random_loot(&self, level: u32) -> Loot<A> {
// decide which type of loot gets dropped
let loot_type_p = Random::range_f32(0.0, 1.0);
let rarity = Rarities::Legendary;
@ -320,7 +321,11 @@ impl ItemSystem {
}
}
pub fn get_random_loot(&self, level: u32, drop_chance_multiplier: Option<f32>) -> Option<Loot> {
pub fn get_random_loot(
&self,
level: u32,
drop_chance_multiplier: Option<f32>,
) -> Option<Loot<A>> {
let drop_chance = match drop_chance_multiplier {
Some(multiplier) => multiplier * self.item_settings.general.drop_chance,
None => self.item_settings.general.drop_chance,
@ -358,7 +363,7 @@ impl ItemSystem {
}
}
pub fn random_ability_book(&self, rarity: Rarities) -> AbilityBook {
pub fn random_ability_book(&self, rarity: Rarities) -> AbilityBook<A> {
let ability = self.random_ability();
let ability_icon = self.ability_icon(ability.name(), rarity);
@ -451,7 +456,7 @@ impl ItemSystem {
rarity: Rarities,
addons: Vec<Option<AbilityAddon>>,
level: u32,
) -> AbilityBook {
) -> AbilityBook<A> {
AbilityBook::load(
self.find_ability(ability_name),
self.ability_icon(ability_name, rarity),
@ -545,7 +550,7 @@ impl ItemSystem {
}
#[inline]
pub fn find_ability(&self, name: &str) -> Ability {
pub fn find_ability(&self, name: &str) -> A {
self.abilities
.iter()
.find(|a| a.name() == name)
@ -554,7 +559,7 @@ impl ItemSystem {
}
#[inline]
pub fn random_ability(&self) -> Ability {
pub fn random_ability(&self) -> A {
let n = Random::range(0, self.abilities.len() as u32);
self.abilities[n as usize].clone()
}

View file

@ -5,7 +5,7 @@ use engine::prelude::*;
use crate::components::inventory::Storable;
use super::{ItemSystem, Rarities};
use super::{ability_book::Ability, ItemSystem, Rarities};
#[derive(Clone)]
pub struct MapItem {
@ -18,9 +18,9 @@ impl MapItem {
pub fn into_persistent(&self) -> String {
String::new()
}
pub fn from_persistent<'a>(
pub fn from_persistent<'a, A: Ability>(
mut _split: impl Iterator<Item = &'a str>,
_item_system: &ItemSystem,
_item_system: &ItemSystem<A>,
) -> Result<Self> {
todo!()
}

View file

@ -7,7 +7,7 @@ use std::{fmt, slice::Iter};
use crate::config::items::{ItemSettings, RarityColorSettings};
use super::ItemSystem;
use super::{ability_book::Ability, ItemSystem};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Rarities {
@ -83,12 +83,12 @@ impl Rarities {
p >= l && p <= h
}
pub fn apply_color(
pub(crate) fn apply_color<A: Ability>(
&self,
base_image: &RgbaImage,
rarity_color_settings: &RarityColorSettings,
) -> RgbaImage {
ItemSystem::apply_color(base_image, rarity_color_settings.from_rarity(*self))
ItemSystem::<A>::apply_color(base_image, rarity_color_settings.from_rarity(*self))
}
}

View file

@ -1,7 +1,4 @@
#[macro_use]
pub mod components;
pub mod ability_type;
pub mod config;
pub mod damage_type;
pub mod items;