From 08c5312a85fb29a01e27f3bcfab6bac6799a077a Mon Sep 17 00:00:00 2001 From: demenik Date: Mon, 1 Dec 2025 15:48:08 +0100 Subject: [PATCH] feat: Add shop buy logic (#34) --- src/features/inventory/components.rs | 73 +++++++++++++++++++++++++++- src/features/shop/components.rs | 21 ++++++++ src/features/shop/mod.rs | 15 +++++- 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/features/inventory/components.rs b/src/features/inventory/components.rs index 69aebba..6bc67a4 100644 --- a/src/features/inventory/components.rs +++ b/src/features/inventory/components.rs @@ -1,4 +1,5 @@ -use crate::{features::config::components::BerrySeedConfig, prelude::*}; +use crate::features::config::components::BerrySeedConfig; +use crate::prelude::*; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] pub enum ItemType { @@ -112,6 +113,76 @@ pub struct Inventory { pub items: Vec, } +impl Inventory { + pub fn update_item_stack( + &mut self, + commands: &mut Commands, + items_query: &mut Query<&mut ItemStack>, + item_type_to_update: ItemType, + amount_delta: i32, + ) -> bool { + let mut target_entity_index: Option = None; + let mut current_stack_amount: u32 = 0; + let mut entity_id_to_update: Option = None; + + // Try to find an existing stack of the item + for (i, &entity) in self.items.iter().enumerate() { + if let Ok(stack) = items_query.get(entity) { + if stack.item_type == item_type_to_update { + target_entity_index = Some(i); + current_stack_amount = stack.amount; + entity_id_to_update = Some(entity); + break; + } + } + } + + match amount_delta { + val if val > 0 => { + // Add items + let add_amount = amount_delta as u32; + if let Some(entity) = entity_id_to_update { + if let Ok(mut stack) = items_query.get_mut(entity) { + stack.amount += add_amount; + } + } else { + // Item not found, create a new stack + let new_item_stack = ItemStack { + item_type: item_type_to_update, + amount: add_amount, + }; + let id = commands.spawn(new_item_stack).id(); + self.items.push(id); + } + true + } + val if val < 0 => { + // Remove items + let remove_amount = amount_delta.abs() as u32; + + let Some(entity) = entity_id_to_update else { + return false; // Item not found for removal + }; + if current_stack_amount < remove_amount { + return false; // Not enough items + }; + + if let Ok(mut stack) = items_query.get_mut(entity) { + stack.amount -= remove_amount; + if stack.amount == 0 { + commands.entity(entity).despawn(); + if let Some(index) = target_entity_index { + self.items.remove(index); + } + } + } + true + } + _ => true, + } + } +} + #[derive(Component)] pub enum RootMarker { Inventory, diff --git a/src/features/shop/components.rs b/src/features/shop/components.rs index ee71abc..3ef70b0 100644 --- a/src/features/shop/components.rs +++ b/src/features/shop/components.rs @@ -50,4 +50,25 @@ impl ShopOffer { offers } + + pub fn buy( + &self, + inventory: &mut Inventory, + commands: &mut Commands, + items: &mut Query<&mut ItemStack>, + ) -> bool { + // Try to remove cost (berries) + if inventory.update_item_stack(commands, items, ItemType::Berry, -(self.cost as i32)) { + inventory.update_item_stack( + commands, + items, + self.item.item_type.clone(), + self.item.amount as i32, + ); + true + } else { + false // Not enough berries + } + } } + diff --git a/src/features/shop/mod.rs b/src/features/shop/mod.rs index ed45ebb..f571ba6 100644 --- a/src/features/shop/mod.rs +++ b/src/features/shop/mod.rs @@ -19,6 +19,8 @@ fn buttons( root_query: Query<(Entity, &RootMarker)>, game_config: Res, asset_server: Res, + mut inventory: ResMut, + mut items: Query<&mut ItemStack>, ) { for (interaction, button_type) in &mut interaction_query { match *interaction { @@ -33,7 +35,18 @@ fn buttons( } } } - _ => {} + ButtonType::ShopBuyItem(offer) => { + if offer.buy(&mut inventory, &mut commands, &mut items) { + // Item bought, exit the menu + for (entity, root) in root_query.iter() { + match *root { + RootMarker::Shop => commands.entity(entity).despawn(), + } + } + } else { + // Error (e.g. not enough berries) + } + } }, _ => {} }