Skillsets now store an ordered vec of skills that is used to track order that skills were acquired in.

This commit is contained in:
Sam 2021-10-22 11:47:06 -04:00
parent 27dd7b4391
commit 356eae85a6
7 changed files with 61 additions and 270 deletions

View File

@ -308,7 +308,8 @@ impl SkillSet {
self.skill_group(skill_group).map_or(0, |s_g| s_g.earned_sp)
}
/// Checks that the skill set contains all prerequisite skills of the required level for a particular skill
/// Checks that the skill set contains all prerequisite skills of the
/// required level for a particular skill
pub fn prerequisites_met(&self, skill: Skill) -> bool {
skill
.prerequisite_skills()
@ -352,7 +353,7 @@ impl SkillSet {
/// Unlocks a skill for a player, assuming they have the relevant skill
/// group unlocked and available SP in that skill group.
pub fn unlock_skill(&mut self, skill: Skill) {
pub fn unlock_skill(&mut self, skill: Skill) -> Result<(), SkillUnlockError> {
if let Some(skill_group_kind) = skill.skill_group_kind() {
let next_level = self.next_skill_level(skill);
let prerequisites_met = self.prerequisites_met(skill);
@ -376,23 +377,29 @@ impl SkillSet {
_ => {},
}
self.skills.insert(skill, next_level);
Ok(())
} else {
trace!("Tried to unlock skill for skill group with insufficient SP");
Err(SkillUnlockError::InsufficientSP)
}
} else {
trace!("Tried to unlock skill without meeting prerequisite skills");
Err(SkillUnlockError::MissingPrerequisites)
}
} else {
trace!("Tried to unlock skill for a skill group that player does not have");
Err(SkillUnlockError::UnavailableSkillGroup)
}
} else {
trace!("Tried to unlock skill the player already has")
trace!("Tried to unlock skill the player already has");
Err(SkillUnlockError::SkillAlreadyUnlocked)
}
} else {
warn!(
?skill,
"Tried to unlock skill that does not exist in any skill group!"
);
Err(SkillUnlockError::NoParentSkillTree)
}
}
@ -439,6 +446,15 @@ pub enum SkillError {
MissingSkill,
}
#[derive(Debug)]
pub enum SkillUnlockError {
InsufficientSP,
MissingPrerequisites,
UnavailableSkillGroup,
SkillAlreadyUnlocked,
NoParentSkillTree,
}
pub enum SpRewardError {
InsufficientExp,
UnavailableSkillGroup,

View File

@ -116,7 +116,10 @@ impl SkillSetBuilder {
}
for _ in 0..level.unwrap_or(1) {
skill_set.add_skill_points(group, skill_set.skill_cost(skill));
skill_set.unlock_skill(skill);
if let Err(err) = skill_set.unlock_skill(skill) {
let err_msg = format!("Failed to add skill: {:?}. Error: {:?}", skill, err);
common_base::dev_panic!(err_msg);
}
}
if !skill_is_applied(skill_set, skill, level) {
let err = format!(

View File

@ -3477,7 +3477,9 @@ fn set_skills(skill_set: &mut comp::SkillSet, preset: &str) -> CmdResult<()> {
for _ in 0..*level {
let cost = skill_set.skill_cost(*skill);
skill_set.add_skill_points(group, cost);
skill_set.unlock_skill(*skill);
skill_set
.unlock_skill(*skill)
.map_err(|err| format!("{:?}", err))?;
}
}
Ok(())

View File

@ -16,8 +16,8 @@ use crate::{
convert_character_from_database, convert_inventory_from_database_items,
convert_items_to_database_items, convert_loadout_from_database_items,
convert_skill_groups_to_database, convert_skill_set_from_database,
convert_stats_from_database,
convert_waypoint_from_database_json, convert_waypoint_to_database_json,
convert_stats_from_database, convert_waypoint_from_database_json,
convert_waypoint_to_database_json,
},
character_loader::{CharacterCreationResult, CharacterDataResult, CharacterListResult},
character_updater::PetPersistenceData,
@ -177,7 +177,7 @@ pub fn load_character_data(
entity_id: char_id,
skill_group_kind: row.get(0)?,
earned_exp: row.get(1)?,
skills: row.get(2)?
skills: row.get(2)?,
})
})?
.filter_map(Result::ok)

View File

@ -408,6 +408,15 @@ pub fn convert_loadout_from_database_items(
Ok(loadout)
}
fn get_item_from_asset(item_definition_id: &str) -> Result<common::comp::Item, PersistenceError> {
common::comp::Item::new_from_asset(item_definition_id).map_err(|err| {
PersistenceError::AssetError(format!(
"Error loading item asset: {} - {}",
item_definition_id, err
))
})
}
/// Generates the code to deserialize a specific body variant from JSON
macro_rules! deserialize_body {
($body_data:expr, $body_variant:tt, $body_type:tt) => {{
@ -501,25 +510,29 @@ pub fn convert_stats_from_database(alias: String) -> common::comp::Stats {
}
pub fn convert_skill_set_from_database(skill_groups: &[SkillGroup]) -> common::comp::SkillSet {
skillset::SkillSet {
skill_groups: convert_skill_groups_from_database(skill_groups),
let (skillless_skill_groups, skills) = convert_skill_groups_from_database(skill_groups);
let unskilled_skillset = skillset::SkillSet {
skill_groups: skillless_skill_groups,
skills: HashMap::new(),
modify_health: true,
modify_energy: true,
};
let mut skillset = unskilled_skillset.clone();
if skills
.iter()
.all(|skill| skillset.unlock_skill(*skill).is_ok())
{
skillset
} else {
unskilled_skillset
}
}
fn get_item_from_asset(item_definition_id: &str) -> Result<common::comp::Item, PersistenceError> {
common::comp::Item::new_from_asset(item_definition_id).map_err(|err| {
PersistenceError::AssetError(format!(
"Error loading item asset: {} - {}",
item_definition_id, err
))
})
}
fn convert_skill_groups_from_database(skill_groups: &[SkillGroup]) -> Vec<skillset::SkillGroup> {
fn convert_skill_groups_from_database(
skill_groups: &[SkillGroup],
) -> (Vec<skillset::SkillGroup>, Vec<skills::Skill>) {
let mut new_skill_groups = Vec::new();
let mut skills = Vec::new();
for skill_group in skill_groups.iter() {
let skill_group_kind = json_models::db_string_to_skill_group(&skill_group.skill_group_kind);
let mut new_skill_group = skillset::SkillGroup {
@ -532,10 +545,13 @@ fn convert_skill_groups_from_database(skill_groups: &[SkillGroup]) -> Vec<skills
};
while new_skill_group.earn_skill_point().is_ok() {}
new_skill_groups.push(new_skill_group);
let mut new_skills =
serde_json::from_str::<Vec<skills::Skill>>(&skill_group.skills).unwrap_or_default();
skills.append(&mut new_skills);
}
new_skill_groups
(new_skill_groups, skills)
}
pub fn convert_skill_groups_to_database(
@ -548,7 +564,8 @@ pub fn convert_skill_groups_to_database(
entity_id,
skill_group_kind: json_models::skill_group_to_db_string(sg.skill_group_kind),
earned_exp: sg.earned_exp as i32,
skills: sg.ordered_skills.iter().map(|s| json_models::skill_to_db_string(*s)).collect(),
// If fails to convert, just forces a respec on next login
skills: serde_json::to_string(&sg.ordered_skills).unwrap_or_else(|_| "".to_string()),
})
.collect()
}

View File

@ -1,7 +1,6 @@
use common::comp;
use serde::{Deserialize, Serialize};
use std::string::ToString;
use tracing::error;
use vek::Vec3;
#[derive(Serialize, Deserialize)]
@ -64,252 +63,6 @@ pub struct CharacterPosition {
pub waypoint: Vec3<f32>,
}
pub fn skill_to_db_string(skill: comp::skills::Skill) -> String {
use comp::{
item::tool::ToolKind,
skills::{
AxeSkill, BowSkill, ClimbSkill, GeneralSkill, HammerSkill, MiningSkill, RollSkill,
SceptreSkill, Skill::*, StaffSkill, SwimSkill, SwordSkill,
},
skillset::SkillGroupKind,
};
let skill_string = match skill {
General(GeneralSkill::HealthIncrease) => "General HealthIncrease",
General(GeneralSkill::EnergyIncrease) => "General EnergyIncrease",
Sword(SwordSkill::InterruptingAttacks) => "Sword InterruptingAttacks",
Sword(SwordSkill::TsCombo) => "Sword TsCombo",
Sword(SwordSkill::TsDamage) => "Sword TsDamage",
Sword(SwordSkill::TsRegen) => "Sword TsRegen",
Sword(SwordSkill::TsSpeed) => "Sword TsSpeed",
Sword(SwordSkill::DCost) => "Sword DCost",
Sword(SwordSkill::DDrain) => "Sword DDrain",
Sword(SwordSkill::DDamage) => "Sword DDamage",
Sword(SwordSkill::DScaling) => "Sword DScaling",
Sword(SwordSkill::DSpeed) => "Sword DSpeed",
Sword(SwordSkill::DInfinite) => "Sword DInfinite",
Sword(SwordSkill::UnlockSpin) => "Sword UnlockSpin",
Sword(SwordSkill::SDamage) => "Sword SDamage",
Sword(SwordSkill::SSpeed) => "Sword SSpeed",
Sword(SwordSkill::SCost) => "Sword SCost",
Sword(SwordSkill::SSpins) => "Sword SSpins",
Axe(AxeSkill::DsCombo) => "Axe DsCombo",
Axe(AxeSkill::DsDamage) => "Axe DsDamage",
Axe(AxeSkill::DsSpeed) => "Axe DsSpeed",
Axe(AxeSkill::DsRegen) => "Axe DsRegen",
Axe(AxeSkill::SInfinite) => "Axe SInfinite",
Axe(AxeSkill::SHelicopter) => "Axe SHelicopter",
Axe(AxeSkill::SDamage) => "Axe SDamage",
Axe(AxeSkill::SSpeed) => "Axe SSpeed",
Axe(AxeSkill::SCost) => "Axe SCost",
Axe(AxeSkill::UnlockLeap) => "Axe UnlockLeap",
Axe(AxeSkill::LDamage) => "Axe LDamage",
Axe(AxeSkill::LKnockback) => "Axe LKnockback",
Axe(AxeSkill::LCost) => "Axe LCost",
Axe(AxeSkill::LDistance) => "Axe LDistance",
Hammer(HammerSkill::SsKnockback) => "Hammer SsKnockback",
Hammer(HammerSkill::SsDamage) => "Hammer SsDamage",
Hammer(HammerSkill::SsSpeed) => "Hammer SsSpeed",
Hammer(HammerSkill::SsRegen) => "Hammer SsRegen",
Hammer(HammerSkill::CDamage) => "Hammer CDamage",
Hammer(HammerSkill::CKnockback) => "Hammer CKnockback",
Hammer(HammerSkill::CDrain) => "Hammer CDrain",
Hammer(HammerSkill::CSpeed) => "Hammer CSpeed",
Hammer(HammerSkill::UnlockLeap) => "Hammer UnlockLeap",
Hammer(HammerSkill::LDamage) => "Hammer LDamage",
Hammer(HammerSkill::LCost) => "Hammer LCost",
Hammer(HammerSkill::LDistance) => "Hammer LDistance",
Hammer(HammerSkill::LKnockback) => "Hammer LKnockback",
Hammer(HammerSkill::LRange) => "Hammer LRange",
Bow(BowSkill::ProjSpeed) => "Bow ProjSpeed",
Bow(BowSkill::CDamage) => "Bow CDamage",
Bow(BowSkill::CRegen) => "Bow CRegen",
Bow(BowSkill::CKnockback) => "Bow CKnockback",
Bow(BowSkill::CSpeed) => "Bow CSpeed",
Bow(BowSkill::CMove) => "Bow CMove",
Bow(BowSkill::RDamage) => "Bow RDamage",
Bow(BowSkill::RCost) => "Bow RCost",
Bow(BowSkill::RSpeed) => "Bow RSpeed",
Bow(BowSkill::UnlockShotgun) => "Bow UnlockShotgun",
Bow(BowSkill::SDamage) => "Bow SDamage",
Bow(BowSkill::SCost) => "Bow SCost",
Bow(BowSkill::SArrows) => "Bow SArrows",
Bow(BowSkill::SSpread) => "Bow SSpread",
Staff(StaffSkill::BDamage) => "Staff BDamage",
Staff(StaffSkill::BRegen) => "Staff BRegen",
Staff(StaffSkill::BRadius) => "Staff BRadius",
Staff(StaffSkill::FDamage) => "Staff FDamage",
Staff(StaffSkill::FRange) => "Staff FRange",
Staff(StaffSkill::FDrain) => "Staff FDrain",
Staff(StaffSkill::FVelocity) => "Staff FVelocity",
Staff(StaffSkill::UnlockShockwave) => "Staff UnlockShockwave",
Staff(StaffSkill::SDamage) => "Staff SDamage",
Staff(StaffSkill::SKnockback) => "Staff SKnockback",
Staff(StaffSkill::SRange) => "Staff SRange",
Staff(StaffSkill::SCost) => "Staff SCost",
Sceptre(SceptreSkill::LDamage) => "Sceptre LDamage",
Sceptre(SceptreSkill::LRange) => "Sceptre LRange",
Sceptre(SceptreSkill::LLifesteal) => "Sceptre LLifesteal",
Sceptre(SceptreSkill::LRegen) => "Sceptre LRegen",
Sceptre(SceptreSkill::HHeal) => "Sceptre HHeal",
Sceptre(SceptreSkill::HDuration) => "Sceptre HDuration",
Sceptre(SceptreSkill::HRange) => "Sceptre HRange",
Sceptre(SceptreSkill::HCost) => "Sceptre HCost",
Sceptre(SceptreSkill::UnlockAura) => "Sceptre UnlockAura",
Sceptre(SceptreSkill::AStrength) => "Sceptre AStrength",
Sceptre(SceptreSkill::ADuration) => "Sceptre ADuration",
Sceptre(SceptreSkill::ARange) => "Sceptre ARange",
Sceptre(SceptreSkill::ACost) => "Sceptre ACost",
Roll(RollSkill::Cost) => "Roll Cost",
Roll(RollSkill::Strength) => "Roll Strength",
Roll(RollSkill::Duration) => "Roll Duration",
Climb(ClimbSkill::Cost) => "Climb Cost",
Climb(ClimbSkill::Speed) => "Climb Speed",
Swim(SwimSkill::Speed) => "Swim Speed",
Pick(MiningSkill::Speed) => "Pick Speed",
Pick(MiningSkill::OreGain) => "Pick OreGain",
Pick(MiningSkill::GemGain) => "Pick GemGain",
UnlockGroup(SkillGroupKind::Weapon(ToolKind::Sword)) => "Unlock Weapon Sword",
UnlockGroup(SkillGroupKind::Weapon(ToolKind::Axe)) => "Unlock Weapon Axe",
UnlockGroup(SkillGroupKind::Weapon(ToolKind::Hammer)) => "Unlock Weapon Hammer",
UnlockGroup(SkillGroupKind::Weapon(ToolKind::Bow)) => "Unlock Weapon Bow",
UnlockGroup(SkillGroupKind::Weapon(ToolKind::Staff)) => "Unlock Weapon Staff",
UnlockGroup(SkillGroupKind::Weapon(ToolKind::Sceptre)) => "Unlock Weapon Sceptre",
UnlockGroup(SkillGroupKind::Weapon(ToolKind::Dagger))
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Shield))
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Spear))
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Debug))
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Farming))
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Pick))
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Empty))
| UnlockGroup(SkillGroupKind::Weapon(ToolKind::Natural))
| UnlockGroup(SkillGroupKind::General) => {
error!("Tried to add unsupported skill to database: {:?}", skill);
"Invalid Skill"
},
};
skill_string.to_string()
}
pub fn db_string_to_skill(skill_string: &str) -> Option<comp::skills::Skill> {
use comp::{
item::tool::ToolKind,
skills::{
AxeSkill, BowSkill, ClimbSkill, GeneralSkill, HammerSkill, MiningSkill, RollSkill,
SceptreSkill, Skill::*, StaffSkill, SwimSkill, SwordSkill,
},
skillset::SkillGroupKind,
};
match skill_string {
"General HealthIncrease" => Some(General(GeneralSkill::HealthIncrease)),
"General EnergyIncrease" => Some(General(GeneralSkill::EnergyIncrease)),
"Sword InterruptingAttacks" => Some(Sword(SwordSkill::InterruptingAttacks)),
"Sword TsCombo" => Some(Sword(SwordSkill::TsCombo)),
"Sword TsDamage" => Some(Sword(SwordSkill::TsDamage)),
"Sword TsRegen" => Some(Sword(SwordSkill::TsRegen)),
"Sword TsSpeed" => Some(Sword(SwordSkill::TsSpeed)),
"Sword DCost" => Some(Sword(SwordSkill::DCost)),
"Sword DDrain" => Some(Sword(SwordSkill::DDrain)),
"Sword DDamage" => Some(Sword(SwordSkill::DDamage)),
"Sword DScaling" => Some(Sword(SwordSkill::DScaling)),
"Sword DSpeed" => Some(Sword(SwordSkill::DSpeed)),
"Sword DInfinite" => Some(Sword(SwordSkill::DInfinite)),
"Sword UnlockSpin" => Some(Sword(SwordSkill::UnlockSpin)),
"Sword SDamage" => Some(Sword(SwordSkill::SDamage)),
"Sword SSpeed" => Some(Sword(SwordSkill::SSpeed)),
"Sword SCost" => Some(Sword(SwordSkill::SCost)),
"Sword SSpins" => Some(Sword(SwordSkill::SSpins)),
"Axe DsCombo" => Some(Axe(AxeSkill::DsCombo)),
"Axe DsDamage" => Some(Axe(AxeSkill::DsDamage)),
"Axe DsSpeed" => Some(Axe(AxeSkill::DsSpeed)),
"Axe DsRegen" => Some(Axe(AxeSkill::DsRegen)),
"Axe SInfinite" => Some(Axe(AxeSkill::SInfinite)),
"Axe SHelicopter" => Some(Axe(AxeSkill::SHelicopter)),
"Axe SDamage" => Some(Axe(AxeSkill::SDamage)),
"Axe SSpeed" => Some(Axe(AxeSkill::SSpeed)),
"Axe SCost" => Some(Axe(AxeSkill::SCost)),
"Axe UnlockLeap" => Some(Axe(AxeSkill::UnlockLeap)),
"Axe LDamage" => Some(Axe(AxeSkill::LDamage)),
"Axe LKnockback" => Some(Axe(AxeSkill::LKnockback)),
"Axe LCost" => Some(Axe(AxeSkill::LCost)),
"Axe LDistance" => Some(Axe(AxeSkill::LDistance)),
"Hammer SsKnockback" => Some(Hammer(HammerSkill::SsKnockback)),
"Hammer SsDamage" => Some(Hammer(HammerSkill::SsDamage)),
"Hammer SsSpeed" => Some(Hammer(HammerSkill::SsSpeed)),
"Hammer SsRegen" => Some(Hammer(HammerSkill::SsRegen)),
"Hammer CDamage" => Some(Hammer(HammerSkill::CDamage)),
"Hammer CKnockback" => Some(Hammer(HammerSkill::CKnockback)),
"Hammer CDrain" => Some(Hammer(HammerSkill::CDrain)),
"Hammer CSpeed" => Some(Hammer(HammerSkill::CSpeed)),
"Hammer UnlockLeap" => Some(Hammer(HammerSkill::UnlockLeap)),
"Hammer LDamage" => Some(Hammer(HammerSkill::LDamage)),
"Hammer LCost" => Some(Hammer(HammerSkill::LCost)),
"Hammer LDistance" => Some(Hammer(HammerSkill::LDistance)),
"Hammer LKnockback" => Some(Hammer(HammerSkill::LKnockback)),
"Hammer LRange" => Some(Hammer(HammerSkill::LRange)),
"Bow ProjSpeed" => Some(Bow(BowSkill::ProjSpeed)),
"Bow CDamage" => Some(Bow(BowSkill::CDamage)),
"Bow CRegen" => Some(Bow(BowSkill::CRegen)),
"Bow CKnockback" => Some(Bow(BowSkill::CKnockback)),
"Bow CSpeed" => Some(Bow(BowSkill::CSpeed)),
"Bow CMove" => Some(Bow(BowSkill::CMove)),
"Bow RDamage" => Some(Bow(BowSkill::RDamage)),
"Bow RCost" => Some(Bow(BowSkill::RCost)),
"Bow RSpeed" => Some(Bow(BowSkill::RSpeed)),
"Bow UnlockShotgun" => Some(Bow(BowSkill::UnlockShotgun)),
"Bow SDamage" => Some(Bow(BowSkill::SDamage)),
"Bow SCost" => Some(Bow(BowSkill::SCost)),
"Bow SArrows" => Some(Bow(BowSkill::SArrows)),
"Bow SSpread" => Some(Bow(BowSkill::SSpread)),
"Staff BDamage" => Some(Staff(StaffSkill::BDamage)),
"Staff BRegen" => Some(Staff(StaffSkill::BRegen)),
"Staff BRadius" => Some(Staff(StaffSkill::BRadius)),
"Staff FDamage" => Some(Staff(StaffSkill::FDamage)),
"Staff FRange" => Some(Staff(StaffSkill::FRange)),
"Staff FDrain" => Some(Staff(StaffSkill::FDrain)),
"Staff FVelocity" => Some(Staff(StaffSkill::FVelocity)),
"Staff UnlockShockwave" => Some(Staff(StaffSkill::UnlockShockwave)),
"Staff SDamage" => Some(Staff(StaffSkill::SDamage)),
"Staff SKnockback" => Some(Staff(StaffSkill::SKnockback)),
"Staff SRange" => Some(Staff(StaffSkill::SRange)),
"Staff SCost" => Some(Staff(StaffSkill::SCost)),
"Sceptre LDamage" => Some(Sceptre(SceptreSkill::LDamage)),
"Sceptre LRange" => Some(Sceptre(SceptreSkill::LRange)),
"Sceptre LLifesteal" => Some(Sceptre(SceptreSkill::LLifesteal)),
"Sceptre LRegen" => Some(Sceptre(SceptreSkill::LRegen)),
"Sceptre HHeal" => Some(Sceptre(SceptreSkill::HHeal)),
"Sceptre HDuration" => Some(Sceptre(SceptreSkill::HDuration)),
"Sceptre HRange" => Some(Sceptre(SceptreSkill::HRange)),
"Sceptre HCost" => Some(Sceptre(SceptreSkill::HCost)),
"Sceptre UnlockAura" => Some(Sceptre(SceptreSkill::UnlockAura)),
"Sceptre AStrength" => Some(Sceptre(SceptreSkill::AStrength)),
"Sceptre ADuration" => Some(Sceptre(SceptreSkill::ADuration)),
"Sceptre ARange" => Some(Sceptre(SceptreSkill::ARange)),
"Sceptre ACost" => Some(Sceptre(SceptreSkill::ACost)),
"Roll Cost" => Some(Roll(RollSkill::Cost)),
"Roll Strength" => Some(Roll(RollSkill::Strength)),
"Roll Duration" => Some(Roll(RollSkill::Duration)),
"Climb Cost" => Some(Climb(ClimbSkill::Cost)),
"Climb Speed" => Some(Climb(ClimbSkill::Speed)),
"Swim Speed" => Some(Swim(SwimSkill::Speed)),
"Pick Speed" => Some(Pick(MiningSkill::Speed)),
"Pick GemGain" => Some(Pick(MiningSkill::GemGain)),
"Pick OreGain" => Some(Pick(MiningSkill::OreGain)),
"Unlock Weapon Sword" => Some(UnlockGroup(SkillGroupKind::Weapon(ToolKind::Sword))),
"Unlock Weapon Axe" => Some(UnlockGroup(SkillGroupKind::Weapon(ToolKind::Axe))),
"Unlock Weapon Hammer" => Some(UnlockGroup(SkillGroupKind::Weapon(ToolKind::Hammer))),
"Unlock Weapon Bow" => Some(UnlockGroup(SkillGroupKind::Weapon(ToolKind::Bow))),
"Unlock Weapon Staff" => Some(UnlockGroup(SkillGroupKind::Weapon(ToolKind::Staff))),
"Unlock Weapon Sceptre" => Some(UnlockGroup(SkillGroupKind::Weapon(ToolKind::Sceptre))),
_ => {
error!(
"Tried to convert an unsupported string from the database: {}",
skill_string
);
None
},
}
}
pub fn skill_group_to_db_string(skill_group: comp::skillset::SkillGroupKind) -> String {
use comp::{item::tool::ToolKind, skillset::SkillGroupKind::*};
let skill_group_string = match skill_group {