Added SkillSetConfig to specify skill sets for npcs.

This commit is contained in:
Sam 2021-01-07 14:47:29 -05:00
parent 968b66260e
commit 6ce422748c
8 changed files with 114 additions and 41 deletions

View File

@ -332,7 +332,7 @@ impl SkillSet {
/// assert_eq!(skillset.skills.len(), 1); /// assert_eq!(skillset.skills.len(), 1);
/// ``` /// ```
pub fn unlock_skill(&mut self, skill: Skill) { pub fn unlock_skill(&mut self, skill: Skill) {
if let Some(skill_group_type) = SkillSet::get_skill_group_type_for_skill(&skill) { if let Some(skill_group_type) = skill.get_skill_group_type() {
let next_level = if self.skills.contains_key(&skill) { let next_level = if self.skills.contains_key(&skill) {
self.skills.get(&skill).copied().flatten().map(|l| l + 1) self.skills.get(&skill).copied().flatten().map(|l| l + 1)
} else { } else {
@ -395,7 +395,7 @@ impl SkillSet {
/// ``` /// ```
pub fn refund_skill(&mut self, skill: Skill) { pub fn refund_skill(&mut self, skill: Skill) {
if self.skills.contains_key(&skill) { if self.skills.contains_key(&skill) {
if let Some(skill_group_type) = SkillSet::get_skill_group_type_for_skill(&skill) { if let Some(skill_group_type) = skill.get_skill_group_type() {
if let Some(mut skill_group) = self if let Some(mut skill_group) = self
.skill_groups .skill_groups
.iter_mut() .iter_mut()
@ -423,18 +423,6 @@ impl SkillSet {
} }
} }
/// Returns the skill group type for a skill from the static skill group
/// definitions.
fn get_skill_group_type_for_skill(skill: &Skill) -> Option<SkillGroupType> {
SKILL_GROUP_DEFS.iter().find_map(|(key, val)| {
if val.contains(&skill) {
Some(*key)
} else {
None
}
})
}
/// Adds skill points to a skill group as long as the player has that skill /// Adds skill points to a skill group as long as the player has that skill
/// group type. /// group type.
/// ///
@ -538,7 +526,7 @@ impl SkillSet {
/// Checks if player has sufficient skill points to purchase a skill /// Checks if player has sufficient skill points to purchase a skill
pub fn sufficient_skill_points(&self, skill: Skill) -> bool { pub fn sufficient_skill_points(&self, skill: Skill) -> bool {
if let Some(skill_group_type) = SkillSet::get_skill_group_type_for_skill(&skill) { if let Some(skill_group_type) = skill.get_skill_group_type() {
if let Some(skill_group) = self if let Some(skill_group) = self
.skill_groups .skill_groups
.iter() .iter()
@ -589,6 +577,18 @@ impl Skill {
/// Returns the maximum level a skill can reach, returns None if the skill /// Returns the maximum level a skill can reach, returns None if the skill
/// doesn't level /// doesn't level
pub fn get_max_level(self) -> Option<u16> { SKILL_MAX_LEVEL.get(&self).copied().flatten() } pub fn get_max_level(self) -> Option<u16> { SKILL_MAX_LEVEL.get(&self).copied().flatten() }
/// Returns the skill group type for a skill from the static skill group
/// definitions.
pub fn get_skill_group_type(self) -> Option<SkillGroupType> {
SKILL_GROUP_DEFS.iter().find_map(|(key, val)| {
if val.contains(&self) {
Some(*key)
} else {
None
}
})
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,6 +1,7 @@
use crate::{ use crate::{
comp::{self, humanoid, inventory::loadout_builder::LoadoutConfig, Alignment, Body, Item}, comp::{self, humanoid, inventory::loadout_builder::LoadoutConfig, Alignment, Body, Item},
npc::{self, NPC_NAMES}, npc::{self, NPC_NAMES},
skillset_builder::SkillSetConfig,
}; };
use vek::*; use vek::*;
@ -23,7 +24,8 @@ pub struct EntityInfo {
// TODO: Properly give NPCs skills // TODO: Properly give NPCs skills
pub level: Option<u16>, pub level: Option<u16>,
pub loot_drop: Option<Item>, pub loot_drop: Option<Item>,
pub config: Option<LoadoutConfig>, pub loadout_config: Option<LoadoutConfig>,
pub skillset_config: Option<SkillSetConfig>,
pub pet: Option<Box<EntityInfo>>, pub pet: Option<Box<EntityInfo>>,
} }
@ -42,7 +44,8 @@ impl EntityInfo {
scale: 1.0, scale: 1.0,
level: None, level: None,
loot_drop: None, loot_drop: None,
config: None, loadout_config: None,
skillset_config: None,
pet: None, pet: None,
} }
} }
@ -109,8 +112,13 @@ impl EntityInfo {
self self
} }
pub fn with_config(mut self, config: LoadoutConfig) -> Self { pub fn with_loadout_config(mut self, config: LoadoutConfig) -> Self {
self.config = Some(config); self.loadout_config = Some(config);
self
}
pub fn with_skillset_config(mut self, config: SkillSetConfig) -> Self {
self.skillset_config = Some(config);
self self
} }

View File

@ -43,6 +43,7 @@ pub mod recipe;
pub mod region; pub mod region;
pub mod resources; pub mod resources;
pub mod rtsim; pub mod rtsim;
pub mod skillset_builder;
pub mod spiral; pub mod spiral;
pub mod states; pub mod states;
pub mod store; pub mod store;
@ -57,3 +58,4 @@ pub mod volumes;
pub use combat::{Damage, DamageSource, GroupTarget, Knockback}; pub use combat::{Damage, DamageSource, GroupTarget, Knockback};
pub use comp::inventory::loadout_builder::LoadoutBuilder; pub use comp::inventory::loadout_builder::LoadoutBuilder;
pub use explosion::{Explosion, RadiusEffect}; pub use explosion::{Explosion, RadiusEffect};
pub use skillset_builder::SkillSetBuilder;

View File

@ -0,0 +1,59 @@
use crate::comp::{
item::tool::ToolKind,
skills::{Skill, SkillGroupType, SkillSet, SwordSkill},
};
use tracing::warn;
#[derive(Copy, Clone)]
pub enum SkillSetConfig {
Guard,
Villager,
Outcast,
Highwayman,
Bandit,
CultistNovice,
CultistAcolyte,
Warlord,
Warlock,
}
pub struct SkillSetBuilder(SkillSet);
impl Default for SkillSetBuilder {
fn default() -> Self { Self(SkillSet::default()) }
}
impl SkillSetBuilder {
pub fn build_skillset(config: SkillSetConfig) -> Self {
let mut skillset = Self::default();
use SkillSetConfig::*;
match config {
Guard => {
skillset.with_skill_group(SkillGroupType::Weapon(ToolKind::Sword));
skillset.with_skill(Skill::Sword(SwordSkill::SUnlockSpin));
},
_ => {},
}
skillset
}
pub fn with_skill(&mut self, skill: Skill) {
if let Some(skill_group) = skill.get_skill_group_type() {
self.0
.add_skill_points(skill_group, self.0.skill_point_cost(skill));
self.0.unlock_skill(skill);
if !self.0.skills.contains_key(&skill) {
warn!(
"Failed to add skill. Verify that it has the appropriate skill group \
available."
);
}
}
}
pub fn with_skill_group(&mut self, skill_group: SkillGroupType) {
self.0.unlock_skill_group(skill_group);
}
pub fn build(self) -> SkillSet { self.0 }
}

View File

@ -9,7 +9,7 @@ use common::{
npc::NPC_NAMES, npc::NPC_NAMES,
span, span,
terrain::TerrainGrid, terrain::TerrainGrid,
LoadoutBuilder, LoadoutBuilder, SkillSetBuilder,
}; };
use common_net::msg::ServerGeneral; use common_net::msg::ServerGeneral;
use common_sys::state::TerrainChanges; use common_sys::state::TerrainChanges;
@ -148,9 +148,13 @@ impl<'a> System<'a> for Sys {
scale = 2.0 + rand::random::<f32>(); scale = 2.0 + rand::random::<f32>();
} }
let config = entity.config; let loadout_config = entity.loadout_config;
let skillset_config = entity.skillset_config;
let loadout = LoadoutBuilder::build_loadout(body, main_tool, config).build(); let loadout = LoadoutBuilder::build_loadout(body, main_tool, loadout_config).build();
if let Some(config) = skillset_config {
stats.skill_set = SkillSetBuilder::build_skillset(config).build();
}
let health = comp::Health::new(stats.body_type, entity.level.unwrap_or(0)); let health = comp::Health::new(stats.body_type, entity.level.unwrap_or(0));
@ -184,7 +188,7 @@ impl<'a> System<'a> for Sys {
can_speak, can_speak,
&body, &body,
matches!( matches!(
config, loadout_config,
Some(comp::inventory::loadout_builder::LoadoutConfig::Guard) Some(comp::inventory::loadout_builder::LoadoutConfig::Guard)
), ),
)) ))

View File

@ -853,7 +853,7 @@ impl Hud {
let scales = ecs.read_storage::<comp::Scale>(); let scales = ecs.read_storage::<comp::Scale>();
let bodies = ecs.read_storage::<comp::Body>(); let bodies = ecs.read_storage::<comp::Body>();
let items = ecs.read_storage::<comp::Item>(); let items = ecs.read_storage::<comp::Item>();
let loadouts = ecs.read_storage::<comp::Loadout>(); let inventories = ecs.read_storage::<comp::Inventory>();
let entities = ecs.entities(); let entities = ecs.entities();
let me = client.entity(); let me = client.entity();
//self.input = client.read_storage::<comp::ControllerInputs>(); //self.input = client.read_storage::<comp::ControllerInputs>();
@ -1276,7 +1276,7 @@ impl Hud {
&bodies, &bodies,
&hp_floater_lists, &hp_floater_lists,
&uids, &uids,
&loadouts, &inventories,
) )
.join() .join()
.filter(|t| { .filter(|t| {
@ -1297,7 +1297,7 @@ impl Hud {
body, body,
hpfl, hpfl,
uid, uid,
loadout, inventory,
)| { )| {
// Use interpolated position if available // Use interpolated position if available
let pos = interpolated.map_or(pos.0, |i| i.pos); let pos = interpolated.map_or(pos.0, |i| i.pos);
@ -1330,7 +1330,7 @@ impl Hud {
health, health,
buffs, buffs,
energy, energy,
combat_rating: combat::combat_rating(loadout, health, &stats.body_type), combat_rating: combat::combat_rating(inventory, health, &stats.body_type),
}); });
let bubble = if dist_sqr < SPEECH_BUBBLE_RANGE.powi(2) { let bubble = if dist_sqr < SPEECH_BUBBLE_RANGE.powi(2) {
speech_bubbles.get(uid) speech_bubbles.get(uid)

View File

@ -599,7 +599,7 @@ impl Floor {
//.do_if(is_giant, |e| e.into_giant()) //.do_if(is_giant, |e| e.into_giant())
.with_body(comp::Body::Humanoid(comp::humanoid::Body::random())) .with_body(comp::Body::Humanoid(comp::humanoid::Body::random()))
.with_alignment(comp::Alignment::Enemy) .with_alignment(comp::Alignment::Enemy)
.with_config(loadout_builder::LoadoutConfig::CultistAcolyte) .with_loadout_config(loadout_builder::LoadoutConfig::CultistAcolyte)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_level(dynamic_rng.gen_range( .with_level(dynamic_rng.gen_range(
(room.difficulty as f32).powf(1.25) + 3.0, (room.difficulty as f32).powf(1.25) + 3.0,
@ -608,7 +608,7 @@ impl Floor {
let entity = match room.difficulty { let entity = match room.difficulty {
0 => entity 0 => entity
.with_name("Outcast") .with_name("Outcast")
.with_config(loadout_builder::LoadoutConfig::Outcast) .with_loadout_config(loadout_builder::LoadoutConfig::Outcast)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
@ -622,7 +622,7 @@ impl Floor {
)), )),
1 => entity 1 => entity
.with_name("Highwayman") .with_name("Highwayman")
.with_config(loadout_builder::LoadoutConfig::Highwayman) .with_loadout_config(loadout_builder::LoadoutConfig::Highwayman)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
@ -636,7 +636,7 @@ impl Floor {
)), )),
2 => entity 2 => entity
.with_name("Bandit") .with_name("Bandit")
.with_config(loadout_builder::LoadoutConfig::Bandit) .with_loadout_config(loadout_builder::LoadoutConfig::Bandit)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
@ -650,7 +650,7 @@ impl Floor {
)), )),
3 => entity 3 => entity
.with_name("Cultist Novice") .with_name("Cultist Novice")
.with_config(loadout_builder::LoadoutConfig::CultistNovice) .with_loadout_config(loadout_builder::LoadoutConfig::CultistNovice)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
@ -664,7 +664,7 @@ impl Floor {
)), )),
4 => entity 4 => entity
.with_name("Cultist Acolyte") .with_name("Cultist Acolyte")
.with_config(loadout_builder::LoadoutConfig::CultistAcolyte) .with_loadout_config(loadout_builder::LoadoutConfig::CultistAcolyte)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
@ -679,14 +679,14 @@ impl Floor {
5 => match dynamic_rng.gen_range(0, 6) { 5 => match dynamic_rng.gen_range(0, 6) {
0 => entity 0 => entity
.with_name("Cultist Warlock") .with_name("Cultist Warlock")
.with_config(loadout_builder::LoadoutConfig::Warlock) .with_loadout_config(loadout_builder::LoadoutConfig::Warlock)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
"common.items.npc_weapons.staff.cultist_staff", "common.items.npc_weapons.staff.cultist_staff",
)), )),
_ => entity _ => entity
.with_name("Cultist Warlord") .with_name("Cultist Warlord")
.with_config(loadout_builder::LoadoutConfig::Warlord) .with_loadout_config(loadout_builder::LoadoutConfig::Warlord)
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 5) { match dynamic_rng.gen_range(0, 5) {
@ -755,7 +755,7 @@ impl Floor {
)) ))
.with_name("Outcast Leader".to_string()) .with_name("Outcast Leader".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_config(loadout_builder::LoadoutConfig::Outcast) .with_loadout_config(loadout_builder::LoadoutConfig::Outcast)
.with_scale(2.0) .with_scale(2.0)
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
@ -801,7 +801,7 @@ impl Floor {
)) ))
.with_name("Bandit Captain".to_string()) .with_name("Bandit Captain".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_config(loadout_builder::LoadoutConfig::Bandit) .with_loadout_config(loadout_builder::LoadoutConfig::Bandit)
.with_scale(2.0) .with_scale(2.0)
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
@ -822,7 +822,7 @@ impl Floor {
)) ))
.with_name("Cultist Acolyte".to_string()) .with_name("Cultist Acolyte".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_config(loadout_builder::LoadoutConfig::CultistAcolyte) .with_loadout_config(loadout_builder::LoadoutConfig::CultistAcolyte)
.with_scale(2.0) .with_scale(2.0)
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {
@ -973,7 +973,7 @@ impl Floor {
)) ))
.with_name("Animal Trainer".to_string()) .with_name("Animal Trainer".to_string())
.with_loot_drop(comp::Item::new_from_asset_expect(chosen)) .with_loot_drop(comp::Item::new_from_asset_expect(chosen))
.with_config(loadout_builder::LoadoutConfig::CultistAcolyte) .with_loadout_config(loadout_builder::LoadoutConfig::CultistAcolyte)
.with_scale(2.0) .with_scale(2.0)
.with_main_tool(comp::Item::new_from_asset_expect( .with_main_tool(comp::Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 6) { match dynamic_rng.gen_range(0, 6) {

View File

@ -934,7 +934,7 @@ impl Settlement {
)) ))
.with_name("Guard") .with_name("Guard")
.with_level(dynamic_rng.gen_range(10, 15)) .with_level(dynamic_rng.gen_range(10, 15))
.with_config(loadout_builder::LoadoutConfig::Guard), .with_loadout_config(loadout_builder::LoadoutConfig::Guard),
_ => entity _ => entity
.with_main_tool(Item::new_from_asset_expect( .with_main_tool(Item::new_from_asset_expect(
match dynamic_rng.gen_range(0, 7) { match dynamic_rng.gen_range(0, 7) {
@ -948,7 +948,7 @@ impl Settlement {
//_ => "common.items.npc_weapons.bow.starter_bow", TODO: Re-Add this when we have a better way of distributing npc_weapons here //_ => "common.items.npc_weapons.bow.starter_bow", TODO: Re-Add this when we have a better way of distributing npc_weapons here
}, },
)) ))
.with_config(loadout_builder::LoadoutConfig::Villager), .with_loadout_config(loadout_builder::LoadoutConfig::Villager),
} }
}); });