Add Exact body field for EntityConfig

Add Alignment field to EntityConfig

+ Migrate to specifying alignment and body in entity assets
+ Make Body required field (with Uninit if you want to specify it later)
This commit is contained in:
juliancoffee 2021-07-04 17:55:52 +03:00
parent 54eb2a3ff7
commit d920f911a2
47 changed files with 252 additions and 181 deletions

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Crazy Sheep"),
body: Some(RandomWith("sheep")),
body: RandomWith("sheep"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.fallback")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Yan Hus"),
body: Some(RandomWith("humanoid")),
body: RandomWith("humanoid"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.fallback")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Big Goose"),
body: Some(RandomWith("goose")),
body: RandomWith("goose"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.fallback")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Harvester"),
body: Some(RandomWith("harvester")),
body: RandomWith("harvester"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-0.boss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Gnarling Stalker"),
body: Some(RandomWith("gnarling")),
body: RandomWith("gnarling"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-0.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Deadwood"),
body: Some(RandomWith("deadwood")),
body: RandomWith("deadwood"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-0.miniboss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Gnarling Mugger"),
body: Some(RandomWith("gnarling")),
body: RandomWith("gnarling"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-0.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Gnarling Shaman"),
body: Some(RandomWith("gnarling")),
body: RandomWith("gnarling"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-0.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Yeti"),
body: Some(RandomWith("yeti")),
body: RandomWith("yeti"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-1.boss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Adlet Tracker"),
body: Some(RandomWith("adlet")),
body: RandomWith("adlet"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-1.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Rat"),
body: Some(RandomWith("rat")),
body: RandomWith("rat"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.creature.quad_small.generic")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Adlet Hunter"),
body: Some(RandomWith("adlet")),
body: RandomWith("adlet"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-1.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Adlet Shaman"),
body: Some(RandomWith("adlet")),
body: RandomWith("adlet"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-1.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Tidal Warrior"),
body: Some(RandomWith("tidalwarrior")),
body: RandomWith("tidalwarrior"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-2.boss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Sahagin Sniper"),
body: Some(RandomWith("sahagin")),
body: RandomWith("sahagin"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-2.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Hakulaq"),
body: Some(RandomWith("hakulaq")),
body: RandomWith("hakulaq"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.creature.quad_low.fanged")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Sahagin Spearman"),
body: Some(RandomWith("sahagin")),
body: RandomWith("sahagin"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-2.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Sahagin Sorcerer"),
body: Some(RandomWith("sahagin")),
body: RandomWith("sahagin"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-2.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Bonerattler"),
body: Some(RandomWith("bonerattler")),
body: RandomWith("bonerattler"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.creature.quad_medium.carapace")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Clay Golem"),
body: Some(RandomWith("claygolem")),
body: RandomWith("claygolem"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-3.boss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Haniwa Archer"),
body: Some(RandomWith("haniwa")),
body: RandomWith("haniwa"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-3.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Haniwa Sentry"),
body: None,
body: Exact(Object(HaniwaSentry)),
alignment: Alignment(Enemy),
loot: Some(Item("common.items.crafting_ing.stones")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Haniwa Guard"),
body: Some(RandomWith("haniwa")),
body: RandomWith("haniwa"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-3.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Haniwa Sorcerer"),
body: Some(RandomWith("haniwa")),
body: RandomWith("haniwa"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-3.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Minotaur"),
body: Some(RandomWith("minotaur")),
body: RandomWith("minotaur"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-4.boss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Myrmidon Marksman"),
body: Some(RandomWith("myrmidon")),
body: RandomWith("myrmidon"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-4.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Dullahan"),
body: Some(RandomWith("dullahan")),
body: RandomWith("dullahan"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-4.miniboss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Myrmidon Hoplite"),
body: Some(RandomWith("myrmidon")),
body: RandomWith("myrmidon"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-4.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Myrmidon Wizard"),
body: Some(RandomWith("myrmidon")),
body: RandomWith("myrmidon"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-4.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Beastmaster"),
body: Some(RandomWith("humanoid")),
body: RandomWith("humanoid"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-5.miniboss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Mindflayer"),
body: Some(RandomWith("mindflayer")),
body: RandomWith("mindflayer"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-5.boss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Cultist"),
body: Some(RandomWith("humanoid")),
body: RandomWith("humanoid"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-5.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Tamed Darkhound"),
body: Some(RandomWith("darkhound")),
body: RandomWith("darkhound"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-5.minion")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Cultist Husk"),
body: Some(RandomWith("husk")),
body: RandomWith("husk"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-5.minion")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Husk Brute"),
body: Some(RandomWith("husk_brute")),
body: RandomWith("husk_brute"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-5.miniboss")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Possessed Turret"),
body: None,
body: Exact(Object(Crossbow)),
alignment: Alignment(Enemy),
loot: Some(Item("common.items.crafting_ing.twigs")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Cultist Warlock"),
body: Some(RandomWith("cultist_warlock")),
body: RandomWith("cultist_warlock"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-5.enemy")),

View File

@ -1,6 +1,7 @@
EntityConfig (
name: Some("Cultist Warlord"),
body: Some(RandomWith("cultist_warlord")),
body: RandomWith("cultist_warlord"),
alignment: Alignment(Enemy),
loot: Some(LootTable("common.loot_tables.dungeon.tier-5.enemy")),

View File

@ -5,7 +5,11 @@ EntityConfig (
/// Body
/// Can be Exact (Body with all fields e.g BodyType, Species, Hair color and such)
/// or RandomWith (will generate random body or species)
body: Some(RandomWith("humanoid")),
/// or Uninit (means it should be specified somewhere in code)
body: RandomWith("humanoid"),
/// Alignment, can be Uninit
alignment: Alignment(Enemy),
/// Main and second tools
/// Can be Option<Item> (with asset_specifier for item)

View File

@ -0,0 +1,13 @@
EntityConfig (
name: Some("Training Dummy"),
body: Exact(Object(TrainingDummy)),
alignment: Alignment(Passive),
loot: None,
main_tool: None,
second_tool: None,
loadout_asset: None,
skillset_asset: None,
)

View File

@ -1,7 +1,7 @@
EntityConfig (
name: Some("Guard"),
// body is specified outsite
body: None,
body: RandomWith("humanoid"),
alignment: Alignment(Npc),
loot: None,

View File

@ -1,7 +1,7 @@
EntityConfig (
name: Some("Merchant"),
// body is specified outsite
body: None,
body: RandomWith("humanoid"),
alignment: Alignment(Npc),
// considering giving some gold/gems/materials?
loot: None,

View File

@ -1,7 +1,8 @@
EntityConfig (
// name is specified outsite
name: None,
// body is specified outsite
body: None,
body: RandomWith("humanoid"),
alignment: Alignment(Npc),
loot: None,

View File

@ -5,6 +5,7 @@ use crate::{
trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult},
uid::Uid,
};
use serde::Deserialize;
use specs::{Component, Entity as EcsEntity};
use specs_idvs::IdvStorage;
use std::{collections::VecDeque, fmt};
@ -16,7 +17,7 @@ pub const DEFAULT_INTERACTION_TIME: f32 = 1.0;
pub const TRADE_INTERACTION_TIME: f32 = 300.0;
pub const MAX_LISTEN_DIST: f32 = 100.0;
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Deserialize)]
pub enum Alignment {
/// Wild animals and gentle giants
Wild,

View File

@ -14,8 +14,10 @@ use serde::Deserialize;
use vek::*;
#[derive(Debug, Deserialize, Clone)]
enum BodyKind {
enum BodyBuilder {
RandomWith(String),
Exact(Body),
Uninit,
}
#[derive(Debug, Deserialize, Clone)]
@ -24,10 +26,17 @@ enum LootKind {
LootTable(String),
}
#[derive(Debug, Deserialize, Clone)]
enum AlignmentMark {
Alignment(Alignment),
Uninit,
}
#[derive(Debug, Deserialize, Clone)]
struct EntityConfig {
name: Option<String>,
body: Option<BodyKind>,
body: BodyBuilder,
alignment: AlignmentMark,
loot: Option<LootKind>,
main_tool: Option<ItemSpec>,
second_tool: Option<ItemSpec>,
@ -101,6 +110,7 @@ impl EntityInfo {
let EntityConfig {
name,
body,
alignment,
loot,
main_tool,
second_tool,
@ -112,17 +122,23 @@ impl EntityInfo {
self = self.with_name(name);
}
if let Some(body) = body {
match body {
BodyKind::RandomWith(string) => {
let npc::NpcBody(_body_kind, mut body_creator) =
string.parse::<npc::NpcBody>().unwrap_or_else(|err| {
panic!("failed to parse body {:?}. Err: {:?}", &string, err)
});
let body = body_creator();
self = self.with_body(body);
},
}
match body {
BodyBuilder::RandomWith(string) => {
let npc::NpcBody(_body_kind, mut body_creator) =
string.parse::<npc::NpcBody>().unwrap_or_else(|err| {
panic!("failed to parse body {:?}. Err: {:?}", &string, err)
});
let body = body_creator();
self = self.with_body(body);
},
BodyBuilder::Exact(body) => {
self = self.with_body(body);
},
BodyBuilder::Uninit => {},
}
if let AlignmentMark::Alignment(alignment) = alignment {
self = self.with_alignment(alignment);
}
if let Some(loot) = loot {
@ -319,9 +335,10 @@ mod tests {
second_tool,
loadout_asset,
skillset_asset,
name: _name,
body,
loot,
name: _name, // can't fail if serialized, it's a boring String
alignment: _alignment, // can't fail if serialized, it's a boring enum
} = config.clone();
if let Some(main_tool) = main_tool {
@ -332,16 +349,15 @@ mod tests {
second_tool.validate(EquipSlot::ActiveOffhand);
}
if let Some(body) = body {
match body {
BodyKind::RandomWith(string) => {
let npc::NpcBody(_body_kind, mut body_creator) =
string.parse::<npc::NpcBody>().unwrap_or_else(|err| {
panic!("failed to parse body {:?}. Err: {:?}", &string, err)
});
let _ = body_creator();
},
}
match body {
BodyBuilder::RandomWith(string) => {
let npc::NpcBody(_body_kind, mut body_creator) =
string.parse::<npc::NpcBody>().unwrap_or_else(|err| {
panic!("failed to parse body {:?}. Err: {:?}", &string, err)
});
let _ = body_creator();
},
BodyBuilder::Exact { .. } | BodyBuilder::Uninit => {},
}
if let Some(loot) = loot {

View File

@ -16,13 +16,13 @@ use crate::{
use common::{
astar::Astar,
comp::{
self, agent, bird_medium, humanoid,
self, agent, bird_medium,
inventory::{
loadout_builder::{make_potion_bag, LoadoutBuilder},
slot::ArmorSlot,
trade_pricing::TradePricing,
},
object, quadruped_small, Item,
quadruped_small, Item,
},
generation::{ChunkSupplement, EntityInfo},
path::Path,
@ -860,7 +860,6 @@ impl Settlement {
}
}
#[allow(clippy::eval_order_dependence)] // TODO: Pending review in #587
pub fn apply_supplement<'a>(
&'a self,
// NOTE: Used only for dynamic elements like chests and entities!
@ -904,75 +903,19 @@ impl Settlement {
if matches!(sample.plot, Some(Plot::Town { .. }))
&& RandomField::new(self.seed).chance(Vec3::from(wpos2d), 1.0 / (50.0 * 40.0))
{
let is_human: bool;
let is_dummy =
RandomField::new(self.seed + 1).chance(Vec3::from(wpos2d), 1.0 / 15.0);
let entity = EntityInfo::at(entity_wpos)
.with_body(match dynamic_rng.gen_range(0..5) {
_ if is_dummy => {
is_human = false;
object::Body::TrainingDummy.into()
},
0 => {
let species = match dynamic_rng.gen_range(0..5) {
0 => quadruped_small::Species::Pig,
1 => quadruped_small::Species::Sheep,
2 => quadruped_small::Species::Goat,
3 => quadruped_small::Species::Dog,
_ => quadruped_small::Species::Cat,
};
is_human = false;
comp::Body::QuadrupedSmall(quadruped_small::Body::random_with(
dynamic_rng,
&species,
))
},
1 => {
let species = match dynamic_rng.gen_range(0..4) {
0 => bird_medium::Species::Duck,
1 => bird_medium::Species::Chicken,
2 => bird_medium::Species::Goose,
_ => bird_medium::Species::Peacock,
};
is_human = false;
comp::Body::BirdMedium(bird_medium::Body::random_with(
dynamic_rng,
&species,
))
},
_ => {
is_human = true;
comp::Body::Humanoid(humanoid::Body::random())
},
})
.with_agency(!is_dummy)
.with_alignment(if is_dummy {
comp::Alignment::Passive
} else if is_human {
comp::Alignment::Npc
} else {
comp::Alignment::Tame
})
.do_if(!is_dummy, |e| e.with_automatic_name())
.do_if(is_dummy, |e| e.with_name("Training Dummy"))
.do_if(is_human && dynamic_rng.gen(), |entity| {
match dynamic_rng.gen_range(0..6) {
0 => entity
.with_agent_mark(agent::Mark::Guard)
.with_lazy_loadout(guard_loadout)
.with_level(dynamic_rng.gen_range(10..15))
.with_asset_expect("common.entity.village.guard"),
1 | 2 => entity
.with_agent_mark(agent::Mark::Merchant)
.with_economy(&economy)
.with_lazy_loadout(merchant_loadout)
.with_level(dynamic_rng.gen_range(10..15))
.with_asset_expect("common.entity.village.merchant"),
_ => entity
.with_lazy_loadout(villager_loadout)
.with_asset_expect("common.entity.village.villager"),
}
});
let entity = if is_dummy {
EntityInfo::at(entity_wpos)
.with_agency(false)
.with_asset_expect("common.entity.village.dummy")
} else {
match dynamic_rng.gen_range(0..=4) {
0 => barnyard(entity_wpos, dynamic_rng),
1 => bird(entity_wpos, dynamic_rng),
_ => human(entity_wpos, &economy, dynamic_rng),
}
};
supplement.add_entity(entity);
}
@ -1031,6 +974,59 @@ impl Settlement {
}
}
fn barnyard(pos: Vec3<f32>, dynamic_rng: &mut impl Rng) -> EntityInfo {
let species = match dynamic_rng.gen_range(0..5) {
0 => quadruped_small::Species::Pig,
1 => quadruped_small::Species::Sheep,
2 => quadruped_small::Species::Goat,
3 => quadruped_small::Species::Dog,
_ => quadruped_small::Species::Cat,
};
EntityInfo::at(pos)
.with_body(comp::Body::QuadrupedSmall(
quadruped_small::Body::random_with(dynamic_rng, &species),
))
.with_alignment(comp::Alignment::Tame)
.with_automatic_name()
}
fn bird(pos: Vec3<f32>, dynamic_rng: &mut impl Rng) -> EntityInfo {
let species = match dynamic_rng.gen_range(0..4) {
0 => bird_medium::Species::Duck,
1 => bird_medium::Species::Chicken,
2 => bird_medium::Species::Goose,
_ => bird_medium::Species::Peacock,
};
EntityInfo::at(pos)
.with_body(comp::Body::BirdMedium(bird_medium::Body::random_with(
dynamic_rng,
&species,
)))
.with_alignment(comp::Alignment::Tame)
.with_automatic_name()
}
fn human(pos: Vec3<f32>, economy: &SiteInformation, dynamic_rng: &mut impl Rng) -> EntityInfo {
let entity = EntityInfo::at(pos);
match dynamic_rng.gen_range(0..12) {
0 => entity
.with_agent_mark(agent::Mark::Guard)
.with_lazy_loadout(guard_loadout)
.with_level(dynamic_rng.gen_range(10..15))
.with_asset_expect("common.entity.village.guard"),
1 | 2 => entity
.with_agent_mark(agent::Mark::Merchant)
.with_economy(&economy)
.with_lazy_loadout(merchant_loadout)
.with_level(dynamic_rng.gen_range(10..15))
.with_asset_expect("common.entity.village.merchant"),
_ => entity
.with_lazy_loadout(villager_loadout)
.with_asset_expect("common.entity.village.villager")
.with_automatic_name(),
}
}
fn merchant_loadout(
loadout_builder: LoadoutBuilder,
economy: Option<&trade::SiteInformation>,

View File

@ -9,7 +9,6 @@ use crate::{
use common::{
assets::{self, AssetExt, AssetHandle},
astar::Astar,
comp::{self},
generation::{ChunkSupplement, EntityInfo},
store::{Id, Store},
terrain::{
@ -235,16 +234,14 @@ impl Room {
for entity in entities {
supplement.add_entity(
entity
.with_level(
dynamic_rng
.gen_range(
(self.difficulty as f32).powf(1.25) + 3.0
..(self.difficulty as f32).powf(1.5) + 4.0,
)
.round() as u16,
)
.with_alignment(comp::Alignment::Enemy),
entity.with_level(
dynamic_rng
.gen_range(
(self.difficulty as f32).powf(1.25) + 3.0
..(self.difficulty as f32).powf(1.5) + 4.0,
)
.round() as u16,
),
);
}
} else {
@ -260,19 +257,13 @@ impl Room {
- 16
})
.map(|e| e as f32 / 16.0);
let turret =
EntityInfo::at(pos.map(|e| e as f32)).with_alignment(comp::Alignment::Enemy);
match self.difficulty {
3 => {
let turret = turret
.with_body(comp::Body::Object(comp::object::Body::HaniwaSentry))
.with_asset_expect("common.entity.dungeon.tier-3.sentry");
let turret = turret_3(pos);
supplement.add_entity(turret);
},
5 => {
let turret = turret
.with_body(comp::Body::Object(comp::object::Body::Crossbow))
.with_asset_expect("common.entity.dungeon.tier-5.turret");
let turret = turret_5(pos);
supplement.add_entity(turret);
},
_ => {},
@ -311,17 +302,15 @@ impl Room {
for entity in entities {
supplement.add_entity(
entity
.with_level(
dynamic_rng
.gen_range(
(self.difficulty as f32).powf(1.25) + 3.0
..(self.difficulty as f32).powf(1.5) + 4.0,
)
.round() as u16
* 5,
)
.with_alignment(comp::Alignment::Enemy),
entity.with_level(
dynamic_rng
.gen_range(
(self.difficulty as f32).powf(1.25) + 3.0
..(self.difficulty as f32).powf(1.5) + 4.0,
)
.round() as u16
* 5,
),
);
}
}
@ -357,17 +346,15 @@ impl Room {
for entity in entities {
supplement.add_entity(
entity
.with_level(
dynamic_rng
.gen_range(
(self.difficulty as f32).powf(1.25) + 3.0
..(self.difficulty as f32).powf(1.5) + 4.0,
)
.round() as u16
* 5,
)
.with_alignment(comp::Alignment::Enemy),
entity.with_level(
dynamic_rng
.gen_range(
(self.difficulty as f32).powf(1.25) + 3.0
..(self.difficulty as f32).powf(1.5) + 4.0,
)
.round() as u16
* 5,
),
);
}
}
@ -789,6 +776,14 @@ fn enemy_fallback(dynamic_rng: &mut impl Rng, tile_wcenter: Vec3<i32>) -> Vec<En
entities
}
fn turret_3(pos: Vec3<f32>) -> EntityInfo {
EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.tier-3.sentry")
}
fn turret_5(pos: Vec3<f32>) -> EntityInfo {
EntityInfo::at(pos).with_asset_expect("common.entity.dungeon.tier-5.turret")
}
fn boss_0(tile_wcenter: Vec3<i32>) -> Vec<EntityInfo> {
vec![
EntityInfo::at(tile_wcenter.map(|e| e as f32))
@ -1441,4 +1436,11 @@ mod tests {
mini_boss_5(&mut dynamic_rng, tile_wcenter);
mini_boss_fallback(tile_wcenter);
}
#[test]
fn test_creating_turrets() {
let pos = Vec3::new(0.0, 0.0, 0.0);
turret_3(pos);
turret_5(pos);
}
}