feat: Add shop logic and popup UI (#34). Update config tests and
defaults
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
"grid_width": 12,
|
"grid_width": 12,
|
||||||
"grid_height": 4,
|
"grid_height": 4,
|
||||||
"pom_speed": 1.5,
|
"pom_speed": 1.5,
|
||||||
|
"shovel_base_price": 10,
|
||||||
|
"shovel_rate": 0.5,
|
||||||
"berry_seeds": [
|
"berry_seeds": [
|
||||||
{
|
{
|
||||||
"name": "Normale Samen",
|
"name": "Normale Samen",
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ pub struct GameConfig {
|
|||||||
pub grid_width: u32,
|
pub grid_width: u32,
|
||||||
pub grid_height: u32,
|
pub grid_height: u32,
|
||||||
pub pom_speed: f32,
|
pub pom_speed: f32,
|
||||||
|
pub shovel_base_price: u32,
|
||||||
|
pub shovel_rate: f32,
|
||||||
pub berry_seeds: Vec<BerrySeedConfig>,
|
pub berry_seeds: Vec<BerrySeedConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +27,8 @@ impl Default for GameConfig {
|
|||||||
grid_width: 12,
|
grid_width: 12,
|
||||||
grid_height: 4,
|
grid_height: 4,
|
||||||
pom_speed: 1.5,
|
pom_speed: 1.5,
|
||||||
|
shovel_base_price: 10,
|
||||||
|
shovel_rate: 0.2,
|
||||||
berry_seeds: vec![
|
berry_seeds: vec![
|
||||||
BerrySeedConfig {
|
BerrySeedConfig {
|
||||||
name: "Normale Samen".to_string(),
|
name: "Normale Samen".to_string(),
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ use crate::{features::config::components::BerrySeedConfig, prelude::*};
|
|||||||
pub enum ItemType {
|
pub enum ItemType {
|
||||||
Berry,
|
Berry,
|
||||||
BerrySeed { name: String },
|
BerrySeed { name: String },
|
||||||
|
Shovel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemType {
|
impl ItemType {
|
||||||
pub fn singular(&self, game_config: &GameConfig) -> String {
|
pub fn singular(&self, game_config: &GameConfig) -> String {
|
||||||
match self {
|
match self {
|
||||||
ItemType::Berry => "Beere".into(),
|
ItemType::Berry => "Beere".into(),
|
||||||
|
ItemType::Shovel => "Schaufel".into(),
|
||||||
ItemType::BerrySeed { name } => {
|
ItemType::BerrySeed { name } => {
|
||||||
let seed_config = game_config.berry_seeds.iter().find(|s| s.name == *name);
|
let seed_config = game_config.berry_seeds.iter().find(|s| s.name == *name);
|
||||||
seed_config
|
seed_config
|
||||||
@@ -22,6 +24,7 @@ impl ItemType {
|
|||||||
pub fn plural(&self, game_config: &GameConfig) -> String {
|
pub fn plural(&self, game_config: &GameConfig) -> String {
|
||||||
match self {
|
match self {
|
||||||
ItemType::Berry => "Beeren".into(),
|
ItemType::Berry => "Beeren".into(),
|
||||||
|
ItemType::Shovel => "Schaufeln".into(),
|
||||||
ItemType::BerrySeed { name } => {
|
ItemType::BerrySeed { name } => {
|
||||||
let seed_config = game_config.berry_seeds.iter().find(|s| s.name == *name);
|
let seed_config = game_config.berry_seeds.iter().find(|s| s.name == *name);
|
||||||
seed_config
|
seed_config
|
||||||
@@ -36,6 +39,7 @@ impl ItemType {
|
|||||||
ItemType::Berry => {
|
ItemType::Berry => {
|
||||||
"Von Pflanzen erntbar. Kann im Shop zum Einkaufen benutzt werden.".into()
|
"Von Pflanzen erntbar. Kann im Shop zum Einkaufen benutzt werden.".into()
|
||||||
}
|
}
|
||||||
|
ItemType::Shovel => "Schaltet ein neues Feld im Garten frei.".into(),
|
||||||
ItemType::BerrySeed { name } => {
|
ItemType::BerrySeed { name } => {
|
||||||
let seed_config = game_config.berry_seeds.iter().find(|s| s.name == *name);
|
let seed_config = game_config.berry_seeds.iter().find(|s| s.name == *name);
|
||||||
if let Some(s) = seed_config {
|
if let Some(s) = seed_config {
|
||||||
@@ -57,7 +61,7 @@ impl ItemType {
|
|||||||
|
|
||||||
pub fn get_seed_config<'a>(&self, game_config: &'a GameConfig) -> Option<&'a BerrySeedConfig> {
|
pub fn get_seed_config<'a>(&self, game_config: &'a GameConfig) -> Option<&'a BerrySeedConfig> {
|
||||||
match self {
|
match self {
|
||||||
ItemType::Berry => None,
|
ItemType::Berry | ItemType::Shovel => None,
|
||||||
ItemType::BerrySeed { name } => {
|
ItemType::BerrySeed { name } => {
|
||||||
game_config.berry_seeds.iter().find(|s| s.name == *name)
|
game_config.berry_seeds.iter().find(|s| s.name == *name)
|
||||||
}
|
}
|
||||||
@@ -70,6 +74,10 @@ impl ItemType {
|
|||||||
name: "Berry".into(),
|
name: "Berry".into(),
|
||||||
aseprite: asset_server.load("berry.aseprite"),
|
aseprite: asset_server.load("berry.aseprite"),
|
||||||
},
|
},
|
||||||
|
ItemType::Shovel => AseSlice {
|
||||||
|
name: "Berry".into(),
|
||||||
|
aseprite: asset_server.load("berry.aseprite"),
|
||||||
|
},
|
||||||
ItemType::BerrySeed { name } => {
|
ItemType::BerrySeed { name } => {
|
||||||
let seed_config = game_config.berry_seeds.iter().find(|s| s.name == *name);
|
let seed_config = game_config.berry_seeds.iter().find(|s| s.name == *name);
|
||||||
if let Some(s) = seed_config {
|
if let Some(s) = seed_config {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ pub mod inventory;
|
|||||||
pub mod phase;
|
pub mod phase;
|
||||||
pub mod pom;
|
pub mod pom;
|
||||||
pub mod savegame;
|
pub mod savegame;
|
||||||
|
pub mod shop;
|
||||||
pub mod start_screen;
|
pub mod start_screen;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
@@ -20,5 +21,6 @@ pub use inventory::InventoryPlugin;
|
|||||||
pub use phase::PhasePlugin;
|
pub use phase::PhasePlugin;
|
||||||
pub use pom::PomPlugin;
|
pub use pom::PomPlugin;
|
||||||
pub use savegame::SavegamePlugin;
|
pub use savegame::SavegamePlugin;
|
||||||
|
pub use shop::ShopPlugin;
|
||||||
pub use start_screen::StartScreenPlugin;
|
pub use start_screen::StartScreenPlugin;
|
||||||
pub use ui::UiPlugin;
|
pub use ui::UiPlugin;
|
||||||
|
|||||||
51
src/features/shop/components.rs
Normal file
51
src/features/shop/components.rs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub enum RootMarker {
|
||||||
|
Shop,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub enum ButtonType {
|
||||||
|
ShopClose,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ShopOffer {
|
||||||
|
pub item: ItemStack,
|
||||||
|
pub cost: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShopOffer {
|
||||||
|
pub fn list_all(game_config: &GameConfig, tile_count: u32) -> Vec<ShopOffer> {
|
||||||
|
let mut offers = Vec::new();
|
||||||
|
|
||||||
|
for seed in &game_config.berry_seeds {
|
||||||
|
offers.push(ShopOffer {
|
||||||
|
item: ItemStack {
|
||||||
|
item_type: ItemType::BerrySeed {
|
||||||
|
name: seed.name.clone(),
|
||||||
|
},
|
||||||
|
amount: 1,
|
||||||
|
},
|
||||||
|
cost: seed.cost,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut shovel_cost = game_config.shovel_base_price as f32;
|
||||||
|
for _ in 0..=tile_count {
|
||||||
|
shovel_cost = shovel_cost + (game_config.shovel_rate * shovel_cost);
|
||||||
|
shovel_cost = shovel_cost.ceil();
|
||||||
|
}
|
||||||
|
|
||||||
|
offers.push(ShopOffer {
|
||||||
|
item: ItemStack {
|
||||||
|
item_type: ItemType::Shovel,
|
||||||
|
amount: 1,
|
||||||
|
},
|
||||||
|
cost: shovel_cost as u32,
|
||||||
|
});
|
||||||
|
|
||||||
|
offers
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/features/shop/mod.rs
Normal file
10
src/features/shop/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub mod components;
|
||||||
|
pub mod ui;
|
||||||
|
|
||||||
|
pub struct ShopPlugin;
|
||||||
|
|
||||||
|
impl Plugin for ShopPlugin {
|
||||||
|
fn build(&self, app: &mut App) {}
|
||||||
|
}
|
||||||
3
src/features/shop/ui/mod.rs
Normal file
3
src/features/shop/ui/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod shop;
|
||||||
|
|
||||||
|
pub use shop::open_shop;
|
||||||
54
src/features/shop/ui/shop.rs
Normal file
54
src/features/shop/ui/shop.rs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
use super::super::components::*;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn open_shop(commands: &mut Commands) {
|
||||||
|
commands
|
||||||
|
.spawn((
|
||||||
|
RootMarker::Shop,
|
||||||
|
Node {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
width: percent(100),
|
||||||
|
height: percent(100),
|
||||||
|
..Node::center()
|
||||||
|
},
|
||||||
|
ZIndex(1),
|
||||||
|
BackgroundColor(Color::srgba(0.0, 0.0, 0.0, 0.8)),
|
||||||
|
GlobalTransform::default(),
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent
|
||||||
|
.spawn((
|
||||||
|
Node {
|
||||||
|
width: px(700),
|
||||||
|
padding: UiRect::all(px(20.0)),
|
||||||
|
..Node::vstack(px(20))
|
||||||
|
},
|
||||||
|
BackgroundColor(Color::srgb(0.2, 0.2, 0.2)),
|
||||||
|
BorderRadius::all(px(10.0)),
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn((
|
||||||
|
Node {
|
||||||
|
justify_content: JustifyContent::SpaceBetween,
|
||||||
|
..Node::hstack(px(20))
|
||||||
|
},
|
||||||
|
children![
|
||||||
|
text("Shop", 40.0, Color::WHITE),
|
||||||
|
pill_button(
|
||||||
|
ButtonType::ShopClose,
|
||||||
|
ButtonVariant::Destructive,
|
||||||
|
Node {
|
||||||
|
width: px(40),
|
||||||
|
height: px(40),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
"X",
|
||||||
|
24.0
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
|
||||||
|
parent.spawn(Node::vstack(px(10))).with_children(|_| {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ fn main() {
|
|||||||
features::SavegamePlugin,
|
features::SavegamePlugin,
|
||||||
features::UiPlugin,
|
features::UiPlugin,
|
||||||
features::InventoryPlugin,
|
features::InventoryPlugin,
|
||||||
|
features::ShopPlugin,
|
||||||
))
|
))
|
||||||
.insert_resource(config)
|
.insert_resource(config)
|
||||||
.run();
|
.run();
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ fn test_load_valid_config() {
|
|||||||
r#"{
|
r#"{
|
||||||
"grid_width": 10,
|
"grid_width": 10,
|
||||||
"grid_height": 5,
|
"grid_height": 5,
|
||||||
"pom_speed": 2.0
|
"pom_speed": 2.0,
|
||||||
|
"shovel_base_price": 10,
|
||||||
|
"shovel_rate": 0.2,
|
||||||
|
"berry_seeds": []
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user