Correctly set the exp target for the next level when spawning a character.

Removed the unwrap_or from the update method for stats persistence, and
have a dedicated method for updating single rows with a new connection.
This commit is contained in:
Shane Handley 2020-05-14 13:48:19 +10:00
parent cbfe3d52fc
commit a41576e767
5 changed files with 57 additions and 21 deletions

View File

@ -85,17 +85,16 @@ impl fmt::Display for StatChangeError {
impl Error for StatChangeError {}
impl Exp {
/// Used to determine how much exp is required to reach the next level. When
/// a character levels up, the next level target is increased by this value
const EXP_INCREASE_FACTOR: u32 = 25;
pub fn current(&self) -> u32 { self.current }
pub fn maximum(&self) -> u32 { self.maximum }
pub fn set_current(&mut self, current: u32) { self.current = current; }
// TODO: Uncomment when needed
// pub fn set_maximum(&mut self, maximum: u32) {
// self.maximum = maximum;
// }
pub fn change_by(&mut self, current: i64) {
self.current = ((self.current as i64) + current) as u32;
}
@ -103,6 +102,10 @@ impl Exp {
pub fn change_maximum_by(&mut self, maximum: i64) {
self.maximum = ((self.maximum as i64) + maximum) as u32;
}
pub fn update_maximum(&mut self, level: u32) {
self.maximum = Self::EXP_INCREASE_FACTOR + (level * Self::EXP_INCREASE_FACTOR);
}
}
impl Level {

View File

@ -64,8 +64,8 @@ impl<'a> System<'a> for Sys {
let stat = stats.get_mut_unchecked();
while stat.exp.current() >= stat.exp.maximum() {
stat.exp.change_by(-(stat.exp.maximum() as i64));
stat.exp.change_maximum_by(25);
stat.level.change_by(1);
stat.exp.update_maximum(stat.level.level());
}
stat.update_max_hp();

View File

@ -78,7 +78,7 @@ pub fn handle_client_disconnect(server: &mut Server, entity: EcsEntity) -> Event
state.read_storage::<comp::Stats>().get(entity),
) {
if let Some(character_id) = player.character_id {
persistence::stats::update(character_id, stats, None, db_dir);
persistence::stats::update_item(character_id, stats, db_dir);
}
}

View File

@ -87,9 +87,13 @@ pub struct Stats {
impl From<StatsJoinData<'_>> for comp::Stats {
fn from(data: StatsJoinData) -> comp::Stats {
let level = data.stats.level as u32;
let mut base_stats = comp::Stats::new(String::from(data.alias), *data.body);
base_stats.level.set_level(data.stats.level as u32);
base_stats.level.set_level(level);
base_stats.exp.update_maximum(level);
base_stats.exp.set_current(data.stats.exp as u32);
base_stats.update_max_hp();
@ -155,4 +159,36 @@ mod tests {
willpower: 4,
})
}
#[test]
fn loads_stats_with_correct_level() {
let data = StatsJoinData {
alias: "test",
body: &comp::Body::from(&Body {
character_id: 0,
race: 0,
body_type: comp::humanoid::BodyType::Female as i16,
hair_style: 0,
beard: 0,
eyebrows: 0,
accessory: 0,
hair_color: 0,
skin: 0,
eye_color: 0,
}),
stats: &Stats {
character_id: 0,
level: 3,
exp: 70,
endurance: 0,
fitness: 2,
willpower: 3,
},
};
let stats = comp::Stats::from(data);
assert_eq!(stats.level.level(), 3);
assert_eq!(stats.exp.current(), 70);
}
}

View File

@ -4,18 +4,11 @@ use super::{establish_connection, models::StatsUpdate, schema};
use crate::comp;
use diesel::prelude::*;
pub fn update(
character_id: i32,
stats: &comp::Stats,
conn: Option<&SqliteConnection>,
db_dir: &str,
) {
log::warn!("stats persisting...");
fn update(character_id: i32, stats: &comp::Stats, connection: &SqliteConnection) {
if let Err(error) =
diesel::update(schema::stats::table.filter(schema::stats::character_id.eq(character_id)))
.set(&StatsUpdate::from(stats))
.execute(conn.unwrap_or(&establish_connection(db_dir)))
.execute(connection)
{
log::warn!(
"Failed to update stats for character: {:?}: {:?}",
@ -25,8 +18,12 @@ pub fn update(
}
}
pub fn batch_update<'a>(updates: impl Iterator<Item = (i32, &'a comp::Stats)>, db_dir: &str) {
let connection = &establish_connection(db_dir);
updates.for_each(|(character_id, stats)| update(character_id, stats, Some(connection), db_dir));
pub fn update_item(character_id: i32, stats: &comp::Stats, db_dir: &str) {
update(character_id, stats, &establish_connection(db_dir));
}
pub fn batch_update<'a>(updates: impl Iterator<Item = (i32, &'a comp::Stats)>, db_dir: &str) {
let connection = establish_connection(db_dir);
updates.for_each(|(character_id, stats)| update(character_id, stats, &connection));
}