Skip to content

Commit b2f0f58

Browse files
committed
Template based spawning
1 parent 524d79c commit b2f0f58

8 files changed

Lines changed: 258 additions & 79 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Templates(
2+
entities: [
3+
Template(
4+
entity_type: Item,
5+
name: "Healing Potion",
6+
texture: HealthPotion,
7+
levels: [0, 1, 2],
8+
provides: Some([("Healing", 6)]),
9+
frequency: 2,
10+
),
11+
Template(
12+
entity_type: Item,
13+
name: "Map",
14+
texture: Map,
15+
levels: [0, 1, 2],
16+
provides: Some([("Map", 6)]),
17+
frequency: 1,
18+
),
19+
Template(
20+
entity_type: Item,
21+
name: "Unsupported Test",
22+
texture: Map,
23+
levels: [0, 1, 2],
24+
provides: Some([("Test", 7)]),
25+
frequency: 2,
26+
),
27+
Template(
28+
entity_type: Enemy,
29+
name: "Bat",
30+
texture: Bat,
31+
levels: [0, 1, 2],
32+
frequency: 3,
33+
hp: Some(1),
34+
),
35+
Template(
36+
entity_type: Enemy,
37+
name: "Ghost",
38+
texture: Ghost,
39+
levels: [0, 1, 2],
40+
frequency: 2,
41+
hp: Some(2),
42+
),
43+
]
44+
)

rustlib/rust_workspace/dungeoncrawl/src/components.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl DerefMut for SelectedItemIndex {
6868
// TODO Make the texture a Rect or something
6969
#[derive(Component, Debug)]
7070
pub struct Render {
71-
pub texture: EntityType,
71+
pub texture: RenderKey,
7272
}
7373

7474
#[derive(Component, Debug)]
@@ -133,7 +133,7 @@ impl PlayerBundle {
133133
max: 20,
134134
},
135135
render: Render {
136-
texture: EntityType::Player,
136+
texture: RenderKey::Player,
137137
},
138138
field_of_view: FieldOfView::new(8),
139139
timer: Timer { time: 0.0 },

rustlib/rust_workspace/dungeoncrawl/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::movement::movement_system;
1414
use crate::prelude::advance_level::advance_level;
1515
use crate::prelude::event_readers::use_item;
1616
use crate::prelude::player_input::player_menu_input_system;
17+
use crate::prelude::template::Templates;
1718
use crate::prelude::*;
1819
use crate::resources::FontResource;
1920
use bevy_app::prelude::*;
@@ -254,4 +255,7 @@ async fn async_bevy_setup(app: &mut App) {
254255

255256
app.insert_resource(sprite_sheet);
256257
app.insert_resource(FontResource(font));
258+
259+
let template = Templates::load().await;
260+
app.insert_resource(template);
257261
}
Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
1-
use crate::prelude::*;
1+
use crate::{prelude::*, spawner::template::Templates};
2+
pub mod template;
23

34
pub fn spawn_player(ecs: &mut Commands, pos: TilePoint) {
45
ecs.spawn(PlayerBundle::new(pos));
56
}
67

7-
pub fn spawn_enemy(ecs: &mut Commands, rng: &mut Rng, pos: TilePoint) {
8-
let (hp, name, render_type) = match rng.i8(0..=10) {
9-
1..=7 => bat(),
10-
_ => giant(),
11-
};
12-
ecs.spawn(EnemyBundle {
13-
enemy: Enemy,
14-
pos,
15-
name: EntityName(name),
16-
health: Health {
17-
current: hp,
18-
max: hp,
19-
},
20-
render: Render {
21-
texture: render_type,
22-
},
23-
field_of_view: FieldOfView::new(6),
24-
movement_behaviour: ChasePlayer,
25-
});
26-
}
8+
// pub fn spawn_enemy(ecs: &mut Commands, rng: &mut Rng, pos: TilePoint) {
9+
// let (hp, name, render_type) = match rng.i8(0..=10) {
10+
// 1..=7 => bat(),
11+
// _ => giant(),
12+
// };
13+
// ecs.spawn(EnemyBundle {
14+
// enemy: Enemy,
15+
// pos,
16+
// name: EntityName(name),
17+
// health: Health {
18+
// current: hp,
19+
// max: hp,
20+
// },
21+
// render: Render {
22+
// texture: render_type,
23+
// },
24+
// field_of_view: FieldOfView::new(6),
25+
// movement_behaviour: ChasePlayer,
26+
// });
27+
// }
2728

2829
pub fn spawn_amulet(ecs: &mut Commands, pos: TilePoint) {
2930
ecs.spawn(AmuletBundle {
@@ -32,47 +33,57 @@ pub fn spawn_amulet(ecs: &mut Commands, pos: TilePoint) {
3233
pos,
3334
name: EntityName("Amulet".to_string()),
3435
render: Render {
35-
texture: EntityType::Amulet,
36+
texture: RenderKey::Amulet,
3637
},
3738
});
3839
}
3940

40-
pub fn spawn_healing_potion(ecs: &mut Commands, pos: TilePoint) {
41-
ecs.spawn((
42-
Item,
43-
pos,
44-
EntityName("Health Potion".to_string()),
45-
ProvidesHealing { amount: 6 },
46-
Render {
47-
texture: EntityType::HealthPotion,
48-
},
49-
));
41+
pub fn spawn_level(
42+
ecs: &mut Commands,
43+
template: &Templates,
44+
rng: &mut Rng,
45+
level: usize,
46+
spawn_points: &[TilePoint],
47+
) {
48+
template.spawn_entities(ecs, rng, level, spawn_points);
5049
}
5150

52-
pub fn spawn_magic_mapper(ecs: &mut Commands, pos: TilePoint) {
53-
ecs.spawn((
54-
Item,
55-
pos,
56-
EntityName("Mapper".to_string()),
57-
ProvidesDungeonMap,
58-
Render {
59-
texture: EntityType::Map,
60-
},
61-
));
62-
}
51+
// pub fn spawn_healing_potion(ecs: &mut Commands, pos: TilePoint) {
52+
// ecs.spawn((
53+
// Item,
54+
// pos,
55+
// EntityName("Health Potion".to_string()),
56+
// ProvidesHealing { amount: 6 },
57+
// Render {
58+
// texture: RenderKey::HealthPotion,
59+
// },
60+
// ));
61+
// }
6362

64-
pub fn spawn_entity(ecs: &mut Commands, pos: TilePoint, rng: &mut Rng) {
65-
match rng.u8(0..6) {
66-
1 => spawn_healing_potion(ecs, pos),
67-
2 => spawn_magic_mapper(ecs, pos),
68-
_ => spawn_enemy(ecs, rng, pos),
69-
}
70-
}
63+
// pub fn spawn_magic_mapper(ecs: &mut Commands, pos: TilePoint) {
64+
// ecs.spawn((
65+
// Item,
66+
// pos,
67+
// EntityName("Mapper".to_string()),
68+
// ProvidesDungeonMap,
69+
// Render {
70+
// texture: RenderKey::Map,
71+
// },
72+
// ));
73+
// }
7174

72-
fn bat() -> (i32, String, EntityType) {
73-
(1, "Goblin".to_string(), EntityType::Bat)
74-
}
75+
// pub fn spawn_entity(ecs: &mut Commands, pos: TilePoint, rng: &mut Rng) {
76+
// match rng.u8(0..6) {
77+
// 1 => spawn_healing_potion(ecs, pos),
78+
// 2 => spawn_magic_mapper(ecs, pos),
79+
// _ => spawn_enemy(ecs, rng, pos),
80+
// }
81+
// }
7582

76-
fn giant() -> (i32, String, EntityType) {
77-
(2, "Giant".to_string(), EntityType::Cyclops)
78-
}
83+
// fn bat() -> (i32, String, RenderKey) {
84+
// (1, "Goblin".to_string(), RenderKey::Bat)
85+
// }
86+
87+
// fn giant() -> (i32, String, RenderKey) {
88+
// (2, "Giant".to_string(), RenderKey::Cyclops)
89+
// }
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use std::collections::HashSet;
2+
3+
use crate::prelude::*;
4+
use serde::Deserialize;
5+
6+
#[derive(Deserialize, Clone, Debug)]
7+
pub struct Template {
8+
pub entity_type: EntityType,
9+
pub levels: HashSet<usize>,
10+
pub frequency: i8,
11+
pub name: String,
12+
pub texture: RenderKey,
13+
pub provides: Option<Vec<(String, i32)>>,
14+
pub hp: Option<i32>,
15+
}
16+
17+
#[derive(Deserialize, Clone, Copy, PartialEq, Debug)]
18+
pub enum EntityType {
19+
Enemy,
20+
Item,
21+
}
22+
23+
#[derive(Resource, Deserialize, Debug)]
24+
pub struct Templates {
25+
entities: Vec<Template>,
26+
}
27+
28+
impl Templates {
29+
pub async fn load() -> Self {
30+
let template_file = load_file("template.ron").await.expect("Template file");
31+
let t = String::from_utf8(template_file.clone()).unwrap();
32+
debug!("{}", t);
33+
match ron::de::from_bytes(&template_file) {
34+
Ok(template) => template,
35+
Err(error) => {
36+
error!("{}", error);
37+
panic!("{}", error);
38+
}
39+
}
40+
}
41+
42+
pub fn spawn_entities(
43+
&self,
44+
commands: &mut Commands,
45+
rng: &mut Rng,
46+
level: usize,
47+
spawn_points: &[TilePoint],
48+
) {
49+
let mut available_entities = Vec::new();
50+
self.entities
51+
.iter()
52+
.filter(|e| e.levels.contains(&level))
53+
.for_each(|e| {
54+
for _ in 0..e.frequency {
55+
available_entities.push(e)
56+
}
57+
});
58+
59+
spawn_points.iter().for_each(|pt| {
60+
if let Some(entity) = rng.choice(&available_entities) {
61+
self.spawn_entity(pt, entity, commands);
62+
}
63+
});
64+
}
65+
66+
fn spawn_entity(&self, pt: &TilePoint, template: &Template, commands: &mut Commands) {
67+
let mut entity = commands.spawn((
68+
*pt,
69+
Render {
70+
texture: template.texture,
71+
},
72+
EntityName(template.name.clone()),
73+
));
74+
75+
match template.entity_type {
76+
EntityType::Item => {
77+
entity.insert(Item);
78+
}
79+
EntityType::Enemy => {
80+
entity
81+
.insert(Enemy)
82+
.insert(FieldOfView::new(6))
83+
.insert(ChasePlayer)
84+
.insert(Health {
85+
current: template.hp.unwrap(),
86+
max: template.hp.unwrap(),
87+
});
88+
}
89+
}
90+
91+
if let Some(effects) = &template.provides {
92+
effects
93+
.iter()
94+
.for_each(|(effect, n)| match effect.as_str() {
95+
"Healing" => {
96+
entity.insert(ProvidesHealing { amount: *n });
97+
}
98+
99+
"Map" => {
100+
entity.insert(ProvidesDungeonMap);
101+
}
102+
103+
_ => error!("Unsupported Effect: {}", effect),
104+
});
105+
}
106+
}
107+
}

rustlib/rust_workspace/dungeoncrawl/src/systems.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ pub mod update_pathfinding;
1616
use crate::PathfindingMap;
1717
use crate::events::{ActivateItem, WantsToAttack, WantsToMove};
1818
use crate::resources::FontResource;
19+
use crate::template::Templates;
1920
use crate::{TurnState, prelude::*};
2021
use bevy_app::Startup;
2122
use bevy_ecs::system::SystemState;
2223
use bevy_state::commands::CommandsStatesExt;
2324
use bracket_pathfinding::prelude::Algorithm2D;
2425

2526
// TODO Make a better way to restart
26-
pub fn setup_system(world: &mut World, p_commands: &mut SystemState<Commands>) {
27+
pub fn setup_system(world: &mut World, p_commands: &mut SystemState<(Commands, Res<Templates>)>) {
2728
info!("setup start");
2829

2930
world.clear_entities();
@@ -41,7 +42,7 @@ pub fn setup_system(world: &mut World, p_commands: &mut SystemState<Commands>) {
4142
.clear();
4243

4344
{
44-
let mut commands = p_commands.get_mut(world);
45+
let (mut commands, template) = p_commands.get_mut(world);
4546

4647
commands.insert_resource(Controller::new());
4748
commands.insert_resource(input_lib::ButtonState::new());
@@ -59,10 +60,13 @@ pub fn setup_system(world: &mut World, p_commands: &mut SystemState<Commands>) {
5960
.point2d_to_index(map_builder.amulet_start.into());
6061
map_builder.map.tiles[exit_idx] = TileType::Stair;
6162

62-
map_builder
63-
.monster_spawns
64-
.iter()
65-
.for_each(|pos| spawn_entity(&mut commands, *pos, &mut rng));
63+
spawn_level(
64+
&mut commands,
65+
&template,
66+
&mut rng,
67+
0,
68+
&map_builder.monster_spawns,
69+
);
6670

6771
commands.insert_resource(Viewport::new(map_builder.player_start));
6872
commands.insert_resource(PathfindingMap::new(&[player_idx], &map_builder.map));

0 commit comments

Comments
 (0)