Start to load EntityInfo from assets in dungeons

* All enemies in dungeons are now specify loadout_config, name and
main_tool in assets
* Add more variance to the enemies names
This commit is contained in:
juliancoffee 2021-06-06 18:55:04 +03:00
parent 5f3eaddb70
commit f5bf991eb0
21 changed files with 292 additions and 98 deletions

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Gnarling Stalker"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.gnarling.adlet_bow")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-0.gnarling"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Gnarling Mugger"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.gnarling.wooden_spear")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-0.gnarling"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Gnarling Shaman"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.gnarling.gnoll_staff")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-0.gnarling"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Adlet Tracker"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.adlet.adlet_bow")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-1.adlet_bow"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Adlet Hunter"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.adlet.wooden_spear")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-1.adlet_spear"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Adlet Shaman"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.adlet.gnoll_staff")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-1.adlet_spear"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Sahagin Sniper"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.sahagin.adlet_bow")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-2.sahagin"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Sahagin Spearman"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.sahagin.wooden_spear")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-2.sahagin"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Sahagin Sorcerer"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.sahagin.gnoll_staff")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-2.sahagin"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Haniwa Archer"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.haniwa.adlet_bow")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-3.haniwa"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Haniwa Guard"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.haniwa.wooden_spear")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-3.haniwa"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Haniwa Sorcerer"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.haniwa.gnoll_staff")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-3.haniwa"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Myrmidon Marksman"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.myrmidon.adlet_bow")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-4.myrmidon"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Myrmidon Hoplite"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.myrmidon.wooden_spear")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-4.myrmidon"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Myrmidon Wizard"),
main_tool: Some(Item("common.items.npc_weapons.biped_small.myrmidon.gnoll_staff")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-4.myrmidon"),
)

View File

@ -0,0 +1,8 @@
EntityConfig (
name: Some("Cultist Warlock"),
main_tool: Some(Item("common.items.weapons.staff.cultist_staff")),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-5.warlock"),
)

View File

@ -0,0 +1,14 @@
EntityConfig (
name: Some("Cultist Warlord"),
main_tool: Some(Choice([
(1.0, Some(Item("common.items.weapons.axe_1h.orichalcum-0"))),
(2.0, Some(Item("common.items.weapons.sword.cultist"))),
(1.0, Some(Item("common.items.weapons.hammer.cultist_purp_2h-0"))),
(1.0, Some(Item("common.items.weapons.hammer_1h.orichalcum-0"))),
(1.0, Some(Item("common.items.weapons.bow.velorite"))),
])),
second_tool: None,
loadout_config: Some("common.loadout.dungeon.tier-5.warlord"),
)

View File

@ -1,4 +1,4 @@
{
EntityConfig (
/// Name of Entity
name: Some("Paddy"),
@ -8,11 +8,6 @@
/// or RandomWith (will use random_with if available for this Body)
// body: Humanoid(Random),
/// Loot
/// Can be Item (with asset_specifier for item)
/// or LootTable (with asset_specifier for loot table)
loot: LootTable("common.loot_tables.humanoids"),
/// Main and second tools
/// Can be Option<Item> (with asset_specifier for item)
/// or Choice
@ -20,12 +15,17 @@
main_tool: Some(Item("common.items.weapons.axe_1h.orichalcum-0")),
second_tool: None,
/// Loadout Config as Option<Loadout> (with asset_specifier for loadout)
loadout_config: Some(Loadout("common.loadout.village.merchant")),
/// Loadout Config (with asset_specifier for loadout)
loadout_config: Some("common.loadout.village.merchant"),
/// Skillset Config as Option<SkillSet> (with asset_specifier for skillset)
// skillset_config: None,
/// Loot
/// Can be Item (with asset_specifier for item)
/// or LootTable (with asset_specifier for loot table)
// loot: LootTable("common.loot_tables.humanoids"),
/// Meta Info (level, alignment, agency, etc)
// meta: {},
}
)

View File

@ -46,7 +46,7 @@ pub enum LoadoutPreset {
}
#[derive(Debug, Deserialize, Clone)]
enum ItemSpec {
pub enum ItemSpec {
/// One specific item.
/// Example:
/// Item("common.items.armor.steel.foot")
@ -61,7 +61,7 @@ enum ItemSpec {
}
impl ItemSpec {
fn try_to_item(&self, asset_specifier: &str, rng: &mut impl Rng) -> Option<Item> {
pub fn try_to_item(&self, asset_specifier: &str, rng: &mut impl Rng) -> Option<Item> {
match self {
ItemSpec::Item(specifier) => Some(Item::new_from_asset_expect(&specifier)),
@ -80,7 +80,7 @@ impl ItemSpec {
#[cfg(test)]
// Read everything and checks if it's loading
fn validate(&self, key: EquipSlot) {
pub fn validate(&self, key: EquipSlot) {
match self {
ItemSpec::Item(specifier) => std::mem::drop(Item::new_from_asset_expect(&specifier)),
ItemSpec::Choice(items) => {

View File

@ -1,7 +1,8 @@
use crate::{
assets::{self, AssetExt},
comp::{
self, agent, humanoid,
inventory::loadout_builder::{LoadoutBuilder, LoadoutPreset},
inventory::loadout_builder::{ItemSpec, LoadoutBuilder, LoadoutPreset},
Alignment, Body, Item,
},
npc::{self, NPC_NAMES},
@ -9,10 +10,21 @@ use crate::{
trade,
trade::SiteInformation,
};
use serde::Deserialize;
use vek::*;
pub enum EntityTemplate {
Traveller,
#[derive(Debug, Deserialize, Clone)]
struct EntityConfig {
name: Option<String>,
main_tool: Option<ItemSpec>,
second_tool: Option<ItemSpec>,
loadout_config: Option<String>,
}
impl assets::Asset for EntityConfig {
type Loader = assets::RonLoader;
const EXTENSION: &'static str = "ron";
}
#[derive(Clone)]
@ -70,6 +82,44 @@ impl EntityInfo {
}
}
pub fn with_asset_expect(self, asset_specifier: &str) -> Self {
let config = EntityConfig::load_expect(asset_specifier).read().clone();
self.with_entity_config(config, Some(asset_specifier))
}
// helper function to apply config
fn with_entity_config(mut self, config: EntityConfig, asset_specifier: Option<&str>) -> Self {
let EntityConfig {
name,
main_tool,
second_tool,
loadout_config,
} = config;
if let Some(name) = name {
self = self.with_name(name);
}
let rng = &mut rand::thread_rng();
if let Some(main_tool) =
main_tool.and_then(|i| i.try_to_item(asset_specifier.unwrap_or("??"), rng))
{
self = self.with_main_tool(main_tool);
}
if let Some(second_tool) =
second_tool.and_then(|i| i.try_to_item(asset_specifier.unwrap_or("??"), rng))
{
self = self.with_main_tool(second_tool);
}
if let Some(loadout_config) = loadout_config {
self = self.with_loadout_config(&loadout_config);
}
self
}
pub fn do_if(mut self, cond: bool, f: impl FnOnce(Self) -> Self) -> Self {
if cond {
self = f(self);
@ -224,3 +274,39 @@ pub fn get_npc_name<
) -> &'a str {
&body_data.species[&species].generic
}
#[cfg(test)]
mod tests {
use super::*;
use assets::Error;
#[test]
fn test_all_entity_assets() {
#[derive(Clone)]
struct EntityList(Vec<EntityConfig>);
impl assets::Compound for EntityList {
fn load<S: assets::source::Source>(
cache: &assets::AssetCache<S>,
specifier: &str,
) -> Result<Self, Error> {
let list = cache
.load::<assets::Directory>(specifier)?
.read()
.iter()
.map(|spec| EntityConfig::load_cloned(spec))
.collect::<Result<_, Error>>()?;
Ok(Self(list))
}
}
// It just load everything that could
// TODO: add some checks, e.g. that Armor(Head) key correspond
// to Item with ItemKind Head(_)
let entity_configs = EntityList::load_expect_cloned("common.entity.*").0;
for config in entity_configs {
let pos = Vec3::new(0.0, 0.0, 0.0);
std::mem::drop(EntityInfo::at(pos).with_entity_config(config, None));
}
}
}

View File

@ -925,24 +925,21 @@ impl Floor {
fn enemy_0(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
let chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.dungeon.tier-0.enemy");
entity
let gnarling = entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Gnarling,
),
))
.with_name("Gnarling")
.with_loadout_config("common.loadout.dungeon.tier-0.gnarling")
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Gnarling)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => "common.items.npc_weapons.biped_small.gnarling.adlet_bow",
1 => "common.items.npc_weapons.biped_small.gnarling.gnoll_staff",
_ => "common.items.npc_weapons.biped_small.gnarling.wooden_spear",
},
))
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Gnarling);
match dynamic_rng.gen_range(0..5) {
0 => gnarling.with_asset_expect("common.entity.dungeon.tier-0.bow"),
1 => gnarling.with_asset_expect("common.entity.dungeon.tier-0.staff"),
_ => gnarling.with_asset_expect("common.entity.dungeon.tier-0.spear"),
}
}
fn enemy_1(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
@ -952,48 +949,33 @@ fn enemy_1(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(dynamic_rng, &comp::biped_small::Species::Adlet),
))
.with_name("Adlet")
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Adlet)
.with_loot_drop(chosen.read().choose().to_item());
match dynamic_rng.gen_range(0..5) {
0 => adlet
.with_main_tool(comp::Item::new_from_asset_expect(
"common.items.npc_weapons.biped_small.adlet.adlet_bow",
))
.with_loadout_config("common.loadout.dungeon.tier-1.adlet_bow"),
1 => adlet
.with_main_tool(comp::Item::new_from_asset_expect(
"common.items.npc_weapons.biped_small.adlet.adlet_staff",
))
.with_loadout_config("common.loadout.dungeon.tier-1.adlet_spear"),
_ => adlet
.with_main_tool(comp::Item::new_from_asset_expect(
"common.items.npc_weapons.biped_small.adlet.adlet_spear",
))
.with_loadout_config("common.loadout.dungeon.tier-1.adlet_spear"),
0 => adlet.with_asset_expect("common.entity.dungeon.tier-1.bow"),
1 => adlet.with_asset_expect("common.entity.dungeon.tier-1.staff"),
_ => adlet.with_asset_expect("common.entity.dungeon.tier-1.spear"),
}
}
fn enemy_2(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
let chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.dungeon.tier-2.enemy");
entity
let sahagin = entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(dynamic_rng, &comp::biped_small::Species::Sahagin),
))
.with_name("Sahagin")
.with_loadout_config("common.loadout.dungeon.tier-2.sahagin")
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Sahagin)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => "common.items.npc_weapons.biped_small.sahagin.adlet_bow",
1 => "common.items.npc_weapons.biped_small.sahagin.gnoll_staff",
_ => "common.items.npc_weapons.biped_small.sahagin.wooden_spear",
},
))
.with_loot_drop(chosen.read().choose().to_item());
match dynamic_rng.gen_range(0..5) {
0 => sahagin.with_asset_expect("common.entity.dungeon.tier-2.bow"),
1 => sahagin.with_asset_expect("common.entity.dungeon.tier-2.staff"),
_ => sahagin.with_asset_expect("common.entity.dungeon.tier-2.spear"),
}
}
fn enemy_3(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
let chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.dungeon.tier-3.enemy");
@ -1004,48 +986,45 @@ fn enemy_3(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
.with_loot_drop(comp::Item::new_from_asset_expect(
"common.items.crafting_ing.stones",
)),
_ => entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Haniwa,
),
))
.with_name("Haniwa")
.with_loadout_config("common.loadout.dungeon.tier-3.haniwa")
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Haniwa)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => "common.items.npc_weapons.biped_small.haniwa.adlet_bow",
1 => "common.items.npc_weapons.biped_small.haniwa.gnoll_staff",
_ => "common.items.npc_weapons.biped_small.haniwa.wooden_spear",
},
)),
_ => {
let haniwa = entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Haniwa,
),
))
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Haniwa)
.with_loot_drop(chosen.read().choose().to_item());
match dynamic_rng.gen_range(0..5) {
0 => haniwa.with_asset_expect("common.entity.dungeon.tier-3.bow"),
1 => haniwa.with_asset_expect("common.entity.dungeon.tier-3.staff"),
_ => haniwa.with_asset_expect("common.entity.dungeon.tier-3.spear"),
}
},
}
}
fn enemy_4(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
let chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.dungeon.tier-4.enemy");
entity
let myrmidon = entity
.with_body(comp::Body::BipedSmall(
comp::biped_small::Body::random_with(
dynamic_rng,
&comp::biped_small::Species::Myrmidon,
),
))
.with_name("Myrmidon")
.with_loadout_config("common.loadout.dungeon.tier-4.myrmidon")
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Myrmidon)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..5) {
0 => "common.items.npc_weapons.biped_small.myrmidon.adlet_bow",
1 => "common.items.npc_weapons.biped_small.myrmidon.gnoll_staff",
_ => "common.items.npc_weapons.biped_small.myrmidon.wooden_spear",
},
))
.with_loot_drop(chosen.read().choose().to_item());
match dynamic_rng.gen_range(0..5) {
0 => myrmidon.with_asset_expect("common.entity.dungeon.tier-4.bow"),
1 => myrmidon.with_asset_expect("common.entity.dungeon.tier-4.staff"),
_ => myrmidon.with_asset_expect("common.entity.dungeon.tier-4.spear"),
}
}
fn enemy_5(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
let chosen = Lottery::<LootSpec>::load_expect("common.loot_tables.dungeon.tier-5.enemy");
@ -1058,27 +1037,14 @@ fn enemy_5(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {
)),
1 => entity
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
.with_name("Cultist Warlock")
.with_loadout_config("common.loadout.dungeon.tier-5.warlock")
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Warlock)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
"common.items.weapons.staff.cultist_staff",
)),
.with_asset_expect("common.entity.dungeon.tier-5.warlock"),
_ => entity
.with_name("Cultist Warlord")
.with_loadout_config("common.loadout.dungeon.tier-5.warlord")
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
.with_skillset_preset(common::skillset_builder::SkillSetConfig::Warlord)
.with_loot_drop(chosen.read().choose().to_item())
.with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0..6) {
0 => "common.items.weapons.axe_1h.orichalcum-0",
1..=2 => "common.items.weapons.sword.cultist",
3 => "common.items.weapons.hammer.cultist_purp_2h-0",
4 => "common.items.weapons.hammer_1h.orichalcum-0",
_ => "common.items.weapons.bow.bone-1",
},
)),
.with_asset_expect("common.entity.dungeon.tier-5.warlord"),
}
}