mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Made skill groups remain locked if skill to unlock them not acquired.
This commit is contained in:
parent
8feb9fb67b
commit
64c8321626
@ -201,8 +201,8 @@ impl SkillGroup {
|
|||||||
/// refunding skills etc.
|
/// refunding skills etc.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct SkillSet {
|
pub struct SkillSet {
|
||||||
pub skill_groups: Vec<SkillGroup>,
|
skill_groups: Vec<SkillGroup>,
|
||||||
pub skills: HashMap<Skill, Option<u16>>,
|
skills: HashMap<Skill, Option<u16>>,
|
||||||
pub modify_health: bool,
|
pub modify_health: bool,
|
||||||
pub modify_energy: bool,
|
pub modify_energy: bool,
|
||||||
}
|
}
|
||||||
@ -221,7 +221,7 @@ impl Default for SkillSet {
|
|||||||
SkillGroup::new(SkillGroupKind::General),
|
SkillGroup::new(SkillGroupKind::General),
|
||||||
SkillGroup::new(SkillGroupKind::Weapon(ToolKind::Pick)),
|
SkillGroup::new(SkillGroupKind::Weapon(ToolKind::Pick)),
|
||||||
],
|
],
|
||||||
skills: HashMap::new(),
|
skills: SkillSet::initial_skills(),
|
||||||
modify_health: false,
|
modify_health: false,
|
||||||
modify_energy: false,
|
modify_energy: false,
|
||||||
}
|
}
|
||||||
@ -229,24 +229,79 @@ impl Default for SkillSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SkillSet {
|
impl SkillSet {
|
||||||
/// Checks if the skill set of an entity contains a particular skill group
|
pub fn initial_skills() -> HashMap<Skill, Option<u16>> {
|
||||||
/// type
|
let mut skills = HashMap::new();
|
||||||
pub fn contains_skill_group(&self, skill_group_kind: SkillGroupKind) -> bool {
|
skills.insert(Skill::UnlockGroup(SkillGroupKind::General), None);
|
||||||
|
skills.insert(
|
||||||
|
Skill::UnlockGroup(SkillGroupKind::Weapon(ToolKind::Pick)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
skills
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_from_database(
|
||||||
|
skill_groups: Vec<SkillGroup>,
|
||||||
|
mut all_skills: HashMap<SkillGroupKind, Vec<Skill>>,
|
||||||
|
) -> Self {
|
||||||
|
let mut skillset = SkillSet {
|
||||||
|
skill_groups,
|
||||||
|
skills: SkillSet::initial_skills(),
|
||||||
|
modify_health: true,
|
||||||
|
modify_energy: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Loops while checking the all_skills hashmap. For as long as it can find an
|
||||||
|
// entry where the skill group kind is unlocked, insert the skills corresponding
|
||||||
|
// to that skill group kind. When no more skill group kinds can be found, break
|
||||||
|
// the loop.
|
||||||
|
while let Some(skill_group_kind) = all_skills
|
||||||
|
.keys()
|
||||||
|
.find(|kind| skillset.has_skill(Skill::UnlockGroup(**kind)))
|
||||||
|
.copied()
|
||||||
|
{
|
||||||
|
// Remove valid skill group kind from the hash map so that loop eventually
|
||||||
|
// terminates.
|
||||||
|
if let Some(skills) = all_skills.remove(&skill_group_kind) {
|
||||||
|
let backup_skillset = skillset.clone();
|
||||||
|
// Iterate over all skills and make sure that unlocking them is successful. If
|
||||||
|
// any fail, fall back to skillset before unlocking any to allow a full respec
|
||||||
|
if !skills
|
||||||
|
.iter()
|
||||||
|
.all(|skill| skillset.unlock_skill(*skill).is_ok())
|
||||||
|
{
|
||||||
|
skillset = backup_skillset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skillset
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a particular skill group is accessible for an entity
|
||||||
|
pub fn skill_group_accessible(&self, skill_group_kind: SkillGroupKind) -> bool {
|
||||||
self.skill_groups
|
self.skill_groups
|
||||||
.iter()
|
.iter()
|
||||||
.any(|x| x.skill_group_kind == skill_group_kind)
|
.any(|x| x.skill_group_kind == skill_group_kind)
|
||||||
|
&& self.has_skill(Skill::UnlockGroup(skill_group_kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unlocks a skill group for a player. It starts with 0 exp and 0 skill
|
/// Unlocks a skill group for a player. It starts with 0 exp and 0 skill
|
||||||
/// points.
|
/// points.
|
||||||
pub fn unlock_skill_group(&mut self, skill_group_kind: SkillGroupKind) {
|
pub fn unlock_skill_group(&mut self, skill_group_kind: SkillGroupKind) {
|
||||||
if !self.contains_skill_group(skill_group_kind) {
|
if !self
|
||||||
|
.skill_groups
|
||||||
|
.iter()
|
||||||
|
.any(|x| x.skill_group_kind == skill_group_kind)
|
||||||
|
{
|
||||||
self.skill_groups.push(SkillGroup::new(skill_group_kind));
|
self.skill_groups.push(SkillGroup::new(skill_group_kind));
|
||||||
} else {
|
} else {
|
||||||
warn!("Tried to unlock already known skill group");
|
warn!("Tried to unlock already known skill group");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over skill groups
|
||||||
|
pub fn skill_groups(&self) -> &Vec<SkillGroup> { &self.skill_groups }
|
||||||
|
|
||||||
/// Returns a reference to a particular skill group in a skillset
|
/// Returns a reference to a particular skill group in a skillset
|
||||||
fn skill_group(&self, skill_group: SkillGroupKind) -> Option<&SkillGroup> {
|
fn skill_group(&self, skill_group: SkillGroupKind) -> Option<&SkillGroup> {
|
||||||
self.skill_groups
|
self.skill_groups
|
||||||
@ -376,32 +431,39 @@ impl SkillSet {
|
|||||||
let prerequisites_met = self.prerequisites_met(skill);
|
let prerequisites_met = self.prerequisites_met(skill);
|
||||||
// Check that skill is not yet at max level
|
// Check that skill is not yet at max level
|
||||||
if !matches!(self.skills.get(&skill), Some(level) if *level == skill.max_level()) {
|
if !matches!(self.skills.get(&skill), Some(level) if *level == skill.max_level()) {
|
||||||
if let Some(mut skill_group) = self.skill_group_mut(skill_group_kind) {
|
if self.has_skill(Skill::UnlockGroup(skill_group_kind)) {
|
||||||
if prerequisites_met {
|
if let Some(mut skill_group) = self.skill_group_mut(skill_group_kind) {
|
||||||
if skill_group.available_sp >= skill.skill_cost(next_level) {
|
if prerequisites_met {
|
||||||
skill_group.available_sp -= skill.skill_cost(next_level);
|
if skill_group.available_sp >= skill.skill_cost(next_level) {
|
||||||
skill_group.ordered_skills.push(skill);
|
skill_group.available_sp -= skill.skill_cost(next_level);
|
||||||
match skill {
|
skill_group.ordered_skills.push(skill);
|
||||||
Skill::UnlockGroup(group) => {
|
match skill {
|
||||||
self.unlock_skill_group(group);
|
Skill::UnlockGroup(group) => {
|
||||||
},
|
self.unlock_skill_group(group);
|
||||||
Skill::General(GeneralSkill::HealthIncrease) => {
|
},
|
||||||
self.modify_health = true;
|
Skill::General(GeneralSkill::HealthIncrease) => {
|
||||||
},
|
self.modify_health = true;
|
||||||
Skill::General(GeneralSkill::EnergyIncrease) => {
|
},
|
||||||
self.modify_energy = true;
|
Skill::General(GeneralSkill::EnergyIncrease) => {
|
||||||
},
|
self.modify_energy = true;
|
||||||
_ => {},
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
self.skills.insert(skill, next_level);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
trace!(
|
||||||
|
"Tried to unlock skill for skill group with insufficient SP"
|
||||||
|
);
|
||||||
|
Err(SkillUnlockError::InsufficientSP)
|
||||||
}
|
}
|
||||||
self.skills.insert(skill, next_level);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
trace!("Tried to unlock skill for skill group with insufficient SP");
|
trace!("Tried to unlock skill without meeting prerequisite skills");
|
||||||
Err(SkillUnlockError::InsufficientSP)
|
Err(SkillUnlockError::MissingPrerequisites)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
trace!("Tried to unlock skill without meeting prerequisite skills");
|
trace!("Tried to unlock skill for a skill group that player does not have");
|
||||||
Err(SkillUnlockError::MissingPrerequisites)
|
Err(SkillUnlockError::UnavailableSkillGroup)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
trace!("Tried to unlock skill for a skill group that player does not have");
|
trace!("Tried to unlock skill for a skill group that player does not have");
|
||||||
|
@ -130,7 +130,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let skills_to_level = skill_set
|
let skills_to_level = skill_set
|
||||||
.skill_groups
|
.skill_groups()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|s_g| {
|
.filter_map(|s_g| {
|
||||||
(s_g.available_experience() >= skill_set.skill_point_cost(s_g.skill_group_kind))
|
(s_g.available_experience() >= skill_set.skill_point_cost(s_g.skill_group_kind))
|
||||||
|
@ -303,7 +303,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
|
|||||||
let contributor_exp = exp_reward * damage_percent;
|
let contributor_exp = exp_reward * damage_percent;
|
||||||
match damage_contributor {
|
match damage_contributor {
|
||||||
DamageContrib::Solo(attacker) => {
|
DamageContrib::Solo(attacker) => {
|
||||||
// No exp for self kills or PvP
|
// No exp for self kills or PvP
|
||||||
if *attacker == entity || is_pvp_kill(*attacker) { return None; }
|
if *attacker == entity || is_pvp_kill(*attacker) { return None; }
|
||||||
|
|
||||||
// Only give EXP to the attacker if they are within EXP range of the killed entity
|
// Only give EXP to the attacker if they are within EXP range of the killed entity
|
||||||
@ -1105,7 +1105,7 @@ fn handle_exp_gain(
|
|||||||
});
|
});
|
||||||
if let Some(weapon) = tool_kind {
|
if let Some(weapon) = tool_kind {
|
||||||
// Only adds to xp pools if entity has that skill group available
|
// Only adds to xp pools if entity has that skill group available
|
||||||
if skill_set.contains_skill_group(SkillGroupKind::Weapon(weapon)) {
|
if skill_set.skill_group_accessible(SkillGroupKind::Weapon(weapon)) {
|
||||||
xp_pools.insert(SkillGroupKind::Weapon(weapon));
|
xp_pools.insert(SkillGroupKind::Weapon(weapon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,7 +419,8 @@ pub fn create_character(
|
|||||||
])?;
|
])?;
|
||||||
drop(stmt);
|
drop(stmt);
|
||||||
|
|
||||||
let db_skill_groups = convert_skill_groups_to_database(character_id, skill_set.skill_groups);
|
let db_skill_groups =
|
||||||
|
convert_skill_groups_to_database(character_id, skill_set.skill_groups().to_vec());
|
||||||
|
|
||||||
let mut stmt = transactionn.prepare_cached(
|
let mut stmt = transactionn.prepare_cached(
|
||||||
"
|
"
|
||||||
@ -559,16 +560,6 @@ pub fn delete_character(
|
|||||||
"Requested character to delete does not belong to the requesting player".to_string(),
|
"Requested character to delete does not belong to the requesting player".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// Delete skills
|
|
||||||
let mut stmt = transaction.prepare_cached(
|
|
||||||
"
|
|
||||||
DELETE
|
|
||||||
FROM skill
|
|
||||||
WHERE entity_id = ?1",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
stmt.execute(&[&char_id])?;
|
|
||||||
drop(stmt);
|
|
||||||
|
|
||||||
// Delete skill groups
|
// Delete skill groups
|
||||||
let mut stmt = transaction.prepare_cached(
|
let mut stmt = transaction.prepare_cached(
|
||||||
@ -1001,7 +992,8 @@ pub fn update(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let db_skill_groups = convert_skill_groups_to_database(char_id, char_skill_set.skill_groups);
|
let db_skill_groups =
|
||||||
|
convert_skill_groups_to_database(char_id, char_skill_set.skill_groups().to_vec());
|
||||||
|
|
||||||
let mut stmt = transaction.prepare_cached(
|
let mut stmt = transaction.prepare_cached(
|
||||||
"
|
"
|
||||||
|
@ -511,28 +511,17 @@ pub fn convert_stats_from_database(alias: String) -> common::comp::Stats {
|
|||||||
|
|
||||||
pub fn convert_skill_set_from_database(skill_groups: &[SkillGroup]) -> common::comp::SkillSet {
|
pub fn convert_skill_set_from_database(skill_groups: &[SkillGroup]) -> common::comp::SkillSet {
|
||||||
let (skillless_skill_groups, skills) = convert_skill_groups_from_database(skill_groups);
|
let (skillless_skill_groups, skills) = convert_skill_groups_from_database(skill_groups);
|
||||||
let unskilled_skillset = skillset::SkillSet {
|
common::comp::SkillSet::load_from_database(skillless_skill_groups, skills)
|
||||||
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 convert_skill_groups_from_database(
|
fn convert_skill_groups_from_database(
|
||||||
skill_groups: &[SkillGroup],
|
skill_groups: &[SkillGroup],
|
||||||
) -> (Vec<skillset::SkillGroup>, Vec<skills::Skill>) {
|
) -> (
|
||||||
|
Vec<skillset::SkillGroup>,
|
||||||
|
HashMap<skillset::SkillGroupKind, Vec<skills::Skill>>,
|
||||||
|
) {
|
||||||
let mut new_skill_groups = Vec::new();
|
let mut new_skill_groups = Vec::new();
|
||||||
let mut skills = Vec::new();
|
let mut all_skills = HashMap::new();
|
||||||
for skill_group in skill_groups.iter() {
|
for skill_group in skill_groups.iter() {
|
||||||
let skill_group_kind = json_models::db_string_to_skill_group(&skill_group.skill_group_kind);
|
let skill_group_kind = json_models::db_string_to_skill_group(&skill_group.skill_group_kind);
|
||||||
let mut new_skill_group = skillset::SkillGroup {
|
let mut new_skill_group = skillset::SkillGroup {
|
||||||
@ -551,17 +540,19 @@ fn convert_skill_groups_from_database(
|
|||||||
// points, and the hash stored of the skill group is the same as the current
|
// points, and the hash stored of the skill group is the same as the current
|
||||||
// hash of the skill group, don't invalidate skills; otherwise invalidate the
|
// hash of the skill group, don't invalidate skills; otherwise invalidate the
|
||||||
// skills in this skill_group.
|
// skills in this skill_group.
|
||||||
if skill_group.spent_exp as u32 == new_skill_group.spent_exp
|
let skills = if skill_group.spent_exp as u32 == new_skill_group.spent_exp
|
||||||
&& Some(&skill_group.hash_val) == skillset::SKILL_GROUP_HASHES.get(&skill_group_kind)
|
&& Some(&skill_group.hash_val) == skillset::SKILL_GROUP_HASHES.get(&skill_group_kind)
|
||||||
{
|
{
|
||||||
let mut new_skills =
|
serde_json::from_str::<Vec<skills::Skill>>(&skill_group.skills).unwrap_or_default()
|
||||||
serde_json::from_str::<Vec<skills::Skill>>(&skill_group.skills).unwrap_or_default();
|
} else {
|
||||||
skills.append(&mut new_skills);
|
Vec::new()
|
||||||
}
|
};
|
||||||
|
|
||||||
|
all_skills.insert(skill_group_kind, skills);
|
||||||
|
|
||||||
new_skill_groups.push(new_skill_group);
|
new_skill_groups.push(new_skill_group);
|
||||||
}
|
}
|
||||||
(new_skill_groups, skills)
|
(new_skill_groups, all_skills)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_skill_groups_to_database(
|
pub fn convert_skill_groups_to_database(
|
||||||
|
@ -370,7 +370,7 @@ impl<'a> Widget for Diary<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check if we have this skill tree unlocked
|
// Check if we have this skill tree unlocked
|
||||||
let locked = !self.skill_set.contains_skill_group(skill_group);
|
let locked = !self.skill_set.skill_group_accessible(skill_group);
|
||||||
|
|
||||||
// Weapon button image
|
// Weapon button image
|
||||||
let btn_img = {
|
let btn_img = {
|
||||||
|
Loading…
Reference in New Issue
Block a user