mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Skill groups now only persist earned_exp instead of available_exp, earned_sp, and available_sp.
This commit is contained in:
parent
0cf0399a47
commit
fe45a158ed
@ -659,7 +659,7 @@ pub enum SkillGroupKind {
|
||||
|
||||
impl SkillGroupKind {
|
||||
/// Gets the cost in experience of earning a skill point
|
||||
pub fn skill_point_cost(self, level: u16) -> u16 {
|
||||
pub fn skill_point_cost(self, level: u16) -> u32 {
|
||||
const EXP_INCREMENT: f32 = 10.0;
|
||||
const STARTING_EXP: f32 = 70.0;
|
||||
const EXP_CEILING: f32 = 1000.0;
|
||||
@ -670,7 +670,7 @@ impl SkillGroupKind {
|
||||
/ (1.0
|
||||
+ std::f32::consts::E.powf(-SCALING_FACTOR * level as f32)
|
||||
* (EXP_CEILING / STARTING_EXP - 1.0)))
|
||||
.floor()) as u16
|
||||
.floor()) as u32
|
||||
}
|
||||
|
||||
/// Gets the total amount of skill points that can be spent in a particular
|
||||
@ -694,7 +694,10 @@ impl SkillGroupKind {
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SkillGroup {
|
||||
pub skill_group_kind: SkillGroupKind,
|
||||
pub exp: u16,
|
||||
// How much exp has been used for skill points
|
||||
pub spent_exp: u32,
|
||||
// How much exp has been earned in total
|
||||
pub earned_exp: u32,
|
||||
pub available_sp: u16,
|
||||
pub earned_sp: u16,
|
||||
}
|
||||
@ -703,11 +706,29 @@ impl SkillGroup {
|
||||
fn new(skill_group_kind: SkillGroupKind) -> SkillGroup {
|
||||
SkillGroup {
|
||||
skill_group_kind,
|
||||
exp: 0,
|
||||
spent_exp: 0,
|
||||
earned_exp: 0,
|
||||
available_sp: 0,
|
||||
earned_sp: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the available experience that could be used to earn another
|
||||
/// skill point in a particular skill group.
|
||||
pub fn available_experience(&self) -> u32 { self.earned_exp - self.spent_exp }
|
||||
|
||||
/// Adds a skill point while subtracting the necessary amount of experience
|
||||
pub fn earn_skill_point(&mut self) -> Result<(), SpRewardError> {
|
||||
let sp_cost = self.skill_group_kind.skill_point_cost(self.earned_sp);
|
||||
if self.available_experience() >= sp_cost {
|
||||
self.spent_exp = self.spent_exp.saturating_add(sp_cost);
|
||||
self.available_sp = self.available_sp.saturating_add(1);
|
||||
self.earned_sp = self.earned_sp.saturating_add(1);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(SpRewardError::InsufficientExp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains all of a player's skill groups and skills. Provides methods for
|
||||
@ -882,12 +903,14 @@ impl SkillSet {
|
||||
}
|
||||
|
||||
/// Adds a skill point while subtracting the necessary amount of experience
|
||||
pub fn earn_skill_point(&mut self, skill_group_kind: SkillGroupKind) {
|
||||
let sp_cost = self.skill_point_cost(skill_group_kind);
|
||||
if let Some(mut skill_group) = self.skill_group_mut(skill_group_kind) {
|
||||
skill_group.exp = skill_group.exp.saturating_sub(sp_cost);
|
||||
skill_group.available_sp = skill_group.available_sp.saturating_add(1);
|
||||
skill_group.earned_sp = skill_group.earned_sp.saturating_add(1);
|
||||
pub fn earn_skill_point(
|
||||
&mut self,
|
||||
skill_group_kind: SkillGroupKind,
|
||||
) -> Result<(), SpRewardError> {
|
||||
if let Some(skill_group) = self.skill_group_mut(skill_group_kind) {
|
||||
skill_group.earn_skill_point()
|
||||
} else {
|
||||
Err(SpRewardError::UnavailableSkillGroup)
|
||||
}
|
||||
}
|
||||
|
||||
@ -901,9 +924,9 @@ impl SkillSet {
|
||||
|
||||
/// Adds/subtracts experience to the skill group within an entity's skill
|
||||
/// set
|
||||
pub fn change_experience(&mut self, skill_group_kind: SkillGroupKind, amount: i32) {
|
||||
pub fn add_experience(&mut self, skill_group_kind: SkillGroupKind, amount: u32) {
|
||||
if let Some(mut skill_group) = self.skill_group_mut(skill_group_kind) {
|
||||
skill_group.exp = (skill_group.exp as i32 + amount) as u16;
|
||||
skill_group.earned_exp = skill_group.earned_exp.saturating_add(amount);
|
||||
} else {
|
||||
warn!("Tried to add experience to a skill group that player does not have");
|
||||
}
|
||||
@ -943,8 +966,9 @@ impl SkillSet {
|
||||
}
|
||||
|
||||
/// Gets the available experience for a particular skill group
|
||||
pub fn experience(&self, skill_group: SkillGroupKind) -> u16 {
|
||||
self.skill_group(skill_group).map_or(0, |s_g| s_g.exp)
|
||||
pub fn available_experience(&self, skill_group: SkillGroupKind) -> u32 {
|
||||
self.skill_group(skill_group)
|
||||
.map_or(0, |s_g| s_g.available_experience())
|
||||
}
|
||||
|
||||
/// Gets skill point cost to purchase skill of next level
|
||||
@ -980,7 +1004,7 @@ impl SkillSet {
|
||||
}
|
||||
|
||||
/// Checks how much experience is needed for the next skill point in a tree
|
||||
pub fn skill_point_cost(&self, skill_group: SkillGroupKind) -> u16 {
|
||||
pub fn skill_point_cost(&self, skill_group: SkillGroupKind) -> u32 {
|
||||
if let Some(level) = self.skill_group(skill_group).map(|sg| sg.earned_sp) {
|
||||
skill_group.skill_point_cost(level)
|
||||
} else {
|
||||
@ -1056,6 +1080,11 @@ impl Skill {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SpRewardError {
|
||||
InsufficientExp,
|
||||
UnavailableSkillGroup,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -36,7 +36,7 @@ pub enum Outcome {
|
||||
},
|
||||
ExpChange {
|
||||
uid: Uid,
|
||||
exp: i32,
|
||||
exp: u32,
|
||||
xp_pools: HashSet<SkillGroupKind>,
|
||||
},
|
||||
SkillPointGain {
|
||||
|
@ -16,6 +16,7 @@ use hashbrown::HashSet;
|
||||
use specs::{
|
||||
shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData, World, Write, WriteStorage,
|
||||
};
|
||||
use tracing::warn;
|
||||
use vek::Vec3;
|
||||
|
||||
const ENERGY_REGEN_ACCEL: f32 = 1.0;
|
||||
@ -132,14 +133,18 @@ impl<'a> System<'a> for Sys {
|
||||
.skill_groups
|
||||
.iter()
|
||||
.filter_map(|s_g| {
|
||||
(s_g.exp >= skill_set.skill_point_cost(s_g.skill_group_kind))
|
||||
(s_g.available_experience() >= skill_set.skill_point_cost(s_g.skill_group_kind))
|
||||
.then(|| s_g.skill_group_kind)
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
if !skills_to_level.is_empty() {
|
||||
for skill_group in skills_to_level {
|
||||
skill_set.earn_skill_point(skill_group);
|
||||
if skill_set.earn_skill_point(skill_group).is_err() {
|
||||
warn!(
|
||||
"Attempted to add skill point to group which is inelgible to earn one"
|
||||
);
|
||||
}
|
||||
outcomes.push(Outcome::SkillPointGain {
|
||||
uid: *uid,
|
||||
skill_tree: skill_group,
|
||||
|
@ -1117,11 +1117,11 @@ fn handle_exp_gain(
|
||||
add_tool_from_slot(EquipSlot::InactiveOffhand);
|
||||
let num_pools = xp_pools.len() as f32;
|
||||
for pool in xp_pools.iter() {
|
||||
skill_set.change_experience(*pool, (exp_reward / num_pools).ceil() as i32);
|
||||
skill_set.add_experience(*pool, (exp_reward / num_pools).ceil() as u32);
|
||||
}
|
||||
outcomes.push(Outcome::ExpChange {
|
||||
uid: *uid,
|
||||
exp: exp_reward as i32,
|
||||
exp: exp_reward as u32,
|
||||
xp_pools,
|
||||
});
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ fn within_mounting_range(player_position: Option<&Pos>, mount_position: Option<&
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ResourceExperienceManifest(HashMap<String, i32>);
|
||||
struct ResourceExperienceManifest(HashMap<String, u32>);
|
||||
|
||||
impl assets::Asset for ResourceExperienceManifest {
|
||||
type Loader = assets::RonLoader;
|
||||
@ -339,7 +339,7 @@ pub fn handle_mine_block(
|
||||
.0
|
||||
.get(item.item_definition_id()),
|
||||
) {
|
||||
skillset.change_experience(SkillGroupKind::Weapon(tool), *exp_reward);
|
||||
skillset.add_experience(SkillGroupKind::Weapon(tool), *exp_reward);
|
||||
state
|
||||
.ecs()
|
||||
.write_resource::<Vec<Outcome>>()
|
||||
|
1
server/src/migrations/V45__skill_persistence.sql
Normal file
1
server/src/migrations/V45__skill_persistence.sql
Normal file
@ -0,0 +1 @@
|
||||
-- Do skill group change of storing (available_exp, available_sp, and earned_sp) to earned_exp
|
@ -196,9 +196,7 @@ pub fn load_character_data(
|
||||
Ok(SkillGroup {
|
||||
entity_id: char_id,
|
||||
skill_group_kind: row.get(0)?,
|
||||
exp: row.get(1)?,
|
||||
available_sp: row.get(2)?,
|
||||
earned_sp: row.get(3)?,
|
||||
earned_exp: row.get(1)?,
|
||||
})
|
||||
})?
|
||||
.filter_map(Result::ok)
|
||||
@ -442,19 +440,15 @@ pub fn create_character(
|
||||
"
|
||||
INSERT INTO skill_group (entity_id,
|
||||
skill_group_kind,
|
||||
exp,
|
||||
available_sp,
|
||||
earned_sp)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
earned_exp)
|
||||
VALUES (?1, ?2, ?3)",
|
||||
)?;
|
||||
|
||||
for skill_group in db_skill_groups {
|
||||
stmt.execute(&[
|
||||
&character_id as &dyn ToSql,
|
||||
&skill_group.skill_group_kind,
|
||||
&skill_group.exp,
|
||||
&skill_group.available_sp,
|
||||
&skill_group.earned_sp,
|
||||
&skill_group.earned_exp,
|
||||
])?;
|
||||
}
|
||||
drop(stmt);
|
||||
@ -1023,19 +1017,15 @@ pub fn update(
|
||||
REPLACE
|
||||
INTO skill_group (entity_id,
|
||||
skill_group_kind,
|
||||
exp,
|
||||
available_sp,
|
||||
earned_sp)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
earned_exp)
|
||||
VALUES (?1, ?2, ?3)",
|
||||
)?;
|
||||
|
||||
for skill_group in db_skill_groups {
|
||||
stmt.execute(&[
|
||||
&skill_group.entity_id as &dyn ToSql,
|
||||
&skill_group.skill_group_kind,
|
||||
&skill_group.exp,
|
||||
&skill_group.available_sp,
|
||||
&skill_group.earned_sp,
|
||||
&skill_group.earned_exp,
|
||||
])?;
|
||||
}
|
||||
|
||||
|
@ -525,12 +525,16 @@ fn convert_skill_groups_from_database(skill_groups: &[SkillGroup]) -> Vec<skills
|
||||
let mut new_skill_groups = 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 new_skill_group = skills::SkillGroup {
|
||||
let mut new_skill_group = skills::SkillGroup {
|
||||
skill_group_kind,
|
||||
exp: skill_group.exp as u16,
|
||||
available_sp: skill_group.available_sp as u16,
|
||||
earned_sp: skill_group.earned_sp as u16,
|
||||
earned_exp: skill_group.earned_exp as u32,
|
||||
spent_exp: 0,
|
||||
available_sp: 0,
|
||||
earned_sp: 0,
|
||||
};
|
||||
|
||||
while new_skill_group.earn_skill_point().is_ok() {}
|
||||
|
||||
new_skill_groups.push(new_skill_group);
|
||||
}
|
||||
new_skill_groups
|
||||
@ -554,9 +558,7 @@ pub fn convert_skill_groups_to_database(
|
||||
.map(|sg| SkillGroup {
|
||||
entity_id,
|
||||
skill_group_kind: json_models::skill_group_to_db_string(sg.skill_group_kind),
|
||||
exp: sg.exp as i32,
|
||||
available_sp: sg.available_sp as i32,
|
||||
earned_sp: sg.earned_sp as i32,
|
||||
earned_exp: sg.earned_exp as i32,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -29,9 +29,7 @@ pub struct Skill {
|
||||
pub struct SkillGroup {
|
||||
pub entity_id: i64,
|
||||
pub skill_group_kind: String,
|
||||
pub exp: i32,
|
||||
pub available_sp: i32,
|
||||
pub earned_sp: i32,
|
||||
pub earned_exp: i32,
|
||||
}
|
||||
|
||||
pub struct Pet {
|
||||
|
@ -464,7 +464,7 @@ impl<'a> Widget for Diary<'a> {
|
||||
}
|
||||
|
||||
// Exp Bars and Rank Display
|
||||
let current_exp = self.skill_set.experience(*sel_tab) as f64;
|
||||
let current_exp = self.skill_set.available_experience(*sel_tab) as f64;
|
||||
let max_exp = self.skill_set.skill_point_cost(*sel_tab) as f64;
|
||||
let exp_percentage = current_exp / max_exp;
|
||||
let rank = self.skill_set.earned_sp(*sel_tab);
|
||||
|
@ -435,7 +435,7 @@ pub struct BuffInfo {
|
||||
|
||||
pub struct ExpFloater {
|
||||
pub owner: Uid,
|
||||
pub exp_change: i32,
|
||||
pub exp_change: u32,
|
||||
pub timer: f32,
|
||||
pub rand_offset: (f32, f32),
|
||||
pub xp_pools: HashSet<SkillGroupKind>,
|
||||
|
Loading…
Reference in New Issue
Block a user