Add experience and leveling up, completing section 5.11
This commit is contained in:
parent
c787ccfd25
commit
dd894452f3
@ -83,16 +83,21 @@ pub struct WantsToMelee {
|
|||||||
|
|
||||||
#[derive(Component, Debug, ConvertSaveload, Clone)]
|
#[derive(Component, Debug, ConvertSaveload, Clone)]
|
||||||
pub struct SufferDamage {
|
pub struct SufferDamage {
|
||||||
pub amount: Vec<i32>,
|
pub amount: Vec<(i32, bool)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SufferDamage {
|
impl SufferDamage {
|
||||||
pub fn new_damage(store: &mut WriteStorage<SufferDamage>, victim: Entity, amount: i32) {
|
pub fn new_damage(
|
||||||
|
store: &mut WriteStorage<SufferDamage>,
|
||||||
|
victim: Entity,
|
||||||
|
amount: i32,
|
||||||
|
from_player: bool,
|
||||||
|
) {
|
||||||
if let Some(suffering) = store.get_mut(victim) {
|
if let Some(suffering) = store.get_mut(victim) {
|
||||||
suffering.amount.push(amount);
|
suffering.amount.push((amount, from_player));
|
||||||
} else {
|
} else {
|
||||||
let dmg = SufferDamage {
|
let dmg = SufferDamage {
|
||||||
amount: vec![amount],
|
amount: vec![(amount, from_player)],
|
||||||
};
|
};
|
||||||
store.insert(victim, dmg).expect("Unable to insert damage");
|
store.insert(victim, dmg).expect("Unable to insert damage");
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,97 @@
|
|||||||
use ::rltk::RandomNumberGenerator;
|
use ::rltk::{Point, RandomNumberGenerator};
|
||||||
use ::specs::prelude::*;
|
use ::specs::prelude::*;
|
||||||
|
use rltk::RGB;
|
||||||
|
|
||||||
use crate::components::{
|
use crate::components::{
|
||||||
Equipped, InBackpack, LootTable, Name, Player, Pools, Position, SufferDamage,
|
Attributes, Equipped, InBackpack, LootTable, Name, Player, Pools, Position, SufferDamage,
|
||||||
};
|
};
|
||||||
use crate::game_log::GameLog;
|
use crate::game_log::GameLog;
|
||||||
|
use crate::gamesystem::{mana_at_level, player_hp_at_level};
|
||||||
|
use crate::particle_system::ParticleBuilder;
|
||||||
use crate::raws::{get_item_drop, spawn_named_item, SpawnType, RAWS};
|
use crate::raws::{get_item_drop, spawn_named_item, SpawnType, RAWS};
|
||||||
use crate::{Map, RunState};
|
use crate::{Map, RunState};
|
||||||
|
|
||||||
pub struct DamageSystem {}
|
pub struct DamageSystem {}
|
||||||
|
|
||||||
impl<'a> System<'a> for DamageSystem {
|
impl<'a> System<'a> for DamageSystem {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
type SystemData = (
|
type SystemData = (
|
||||||
WriteStorage<'a, Pools>,
|
WriteStorage<'a, Pools>,
|
||||||
WriteStorage<'a, SufferDamage>,
|
WriteStorage<'a, SufferDamage>,
|
||||||
ReadStorage<'a, Position>,
|
ReadStorage<'a, Position>,
|
||||||
WriteExpect<'a, Map>,
|
WriteExpect<'a, Map>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
|
ReadExpect<'a, Entity>,
|
||||||
|
ReadStorage<'a, Attributes>,
|
||||||
|
WriteExpect<'a, GameLog>,
|
||||||
|
WriteExpect<'a, ParticleBuilder>,
|
||||||
|
ReadExpect<'a, Point>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
let (mut stats, mut damage, positions, mut map, entities) = data;
|
let (
|
||||||
|
mut stats,
|
||||||
|
mut damage,
|
||||||
|
positions,
|
||||||
|
mut map,
|
||||||
|
entities,
|
||||||
|
player,
|
||||||
|
attributes,
|
||||||
|
mut log,
|
||||||
|
mut particles,
|
||||||
|
player_pos,
|
||||||
|
) = data;
|
||||||
|
let mut xp_gain = 0;
|
||||||
|
|
||||||
for (entity, mut stats, damage) in (&entities, &mut stats, &damage).join() {
|
for (entity, mut stats, damage) in (&entities, &mut stats, &damage).join() {
|
||||||
stats.hit_points.current -= damage.amount.iter().sum::<i32>();
|
for dmg in damage.amount.iter() {
|
||||||
|
stats.hit_points.current -= dmg.0;
|
||||||
if let Some(pos) = positions.get(entity) {
|
if let Some(pos) = positions.get(entity) {
|
||||||
let idx = map.xy_idx(pos.x, pos.y);
|
let idx = map.xy_idx(pos.x, pos.y);
|
||||||
map.bloodstains.insert(idx);
|
map.bloodstains.insert(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if stats.hit_points.current < 1 && dmg.1 {
|
||||||
|
xp_gain += stats.level * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if xp_gain != 0 {
|
||||||
|
let mut player_stats = stats.get_mut(*player).unwrap();
|
||||||
|
let player_attributes = attributes.get(*player).unwrap();
|
||||||
|
player_stats.xp += xp_gain;
|
||||||
|
if player_stats.xp >= player_stats.level * 1000 {
|
||||||
|
// We've gone up a level!
|
||||||
|
player_stats.level += 1;
|
||||||
|
log.append(format!(
|
||||||
|
"Congratulations, you are now level {}",
|
||||||
|
player_stats.level
|
||||||
|
));
|
||||||
|
player_stats.hit_points.max = player_hp_at_level(
|
||||||
|
player_attributes.fitness.base + player_attributes.fitness.modifiers,
|
||||||
|
player_stats.level,
|
||||||
|
);
|
||||||
|
player_stats.hit_points.current = player_stats.hit_points.max;
|
||||||
|
player_stats.mana.max = mana_at_level(
|
||||||
|
player_attributes.intelligence.base + player_attributes.intelligence.modifiers,
|
||||||
|
player_stats.level,
|
||||||
|
);
|
||||||
|
player_stats.mana.current = player_stats.mana.max;
|
||||||
|
|
||||||
|
for i in 0..10 {
|
||||||
|
if player_pos.y - i > 1 {
|
||||||
|
particles.request(
|
||||||
|
player_pos.x,
|
||||||
|
player_pos.y - 1,
|
||||||
|
RGB::named(rltk::GOLD),
|
||||||
|
RGB::named(rltk::BLACK),
|
||||||
|
rltk::to_cp437('░'),
|
||||||
|
400.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
damage.clear();
|
damage.clear();
|
||||||
|
12
src/gui.rs
12
src/gui.rs
@ -82,8 +82,10 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
|||||||
"Mana: {}/{}",
|
"Mana: {}/{}",
|
||||||
player_pools.mana.current, player_pools.mana.max
|
player_pools.mana.current, player_pools.mana.max
|
||||||
);
|
);
|
||||||
|
let xp = format!("Level: {}", player_pools.level);
|
||||||
ctx.print_color(50, 1, white, black, &health);
|
ctx.print_color(50, 1, white, black, &health);
|
||||||
ctx.print_color(50, 2, white, black, &mana);
|
ctx.print_color(50, 2, white, black, &mana);
|
||||||
|
ctx.print_color(50, 3, white, black, &xp);
|
||||||
ctx.draw_bar_horizontal(
|
ctx.draw_bar_horizontal(
|
||||||
64,
|
64,
|
||||||
1,
|
1,
|
||||||
@ -102,6 +104,16 @@ pub fn draw_ui(ecs: &World, ctx: &mut Rltk) {
|
|||||||
RGB::named(rltk::BLUE),
|
RGB::named(rltk::BLUE),
|
||||||
RGB::named(rltk::BLACK),
|
RGB::named(rltk::BLACK),
|
||||||
);
|
);
|
||||||
|
let xp_level_start = (player_pools.level - 1) * 1000;
|
||||||
|
ctx.draw_bar_horizontal(
|
||||||
|
64,
|
||||||
|
3,
|
||||||
|
14,
|
||||||
|
player_pools.xp - xp_level_start,
|
||||||
|
1000,
|
||||||
|
RGB::named(rltk::GOLD),
|
||||||
|
black,
|
||||||
|
);
|
||||||
|
|
||||||
// Attributes
|
// Attributes
|
||||||
let attributes = ecs.read_storage::<Attributes>();
|
let attributes = ecs.read_storage::<Attributes>();
|
||||||
|
@ -73,7 +73,7 @@ impl<'a> System<'a> for HungerSystem {
|
|||||||
log.append("Your hunger pangs are getting painful!");
|
log.append("Your hunger pangs are getting painful!");
|
||||||
}
|
}
|
||||||
|
|
||||||
SufferDamage::new_damage(&mut inflict_damage, entity, 1);
|
SufferDamage::new_damage(&mut inflict_damage, entity, 1, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,7 @@ impl<'a> System<'a> for ItemUseSystem {
|
|||||||
used_item = false;
|
used_item = false;
|
||||||
|
|
||||||
for mob in targets.iter() {
|
for mob in targets.iter() {
|
||||||
SufferDamage::new_damage(&mut suffer_damage, *mob, damage.damage);
|
SufferDamage::new_damage(&mut suffer_damage, *mob, damage.damage, true);
|
||||||
if entity == *player_entity {
|
if entity == *player_entity {
|
||||||
let mob_name = names.get(*mob).unwrap();
|
let mob_name = names.get(*mob).unwrap();
|
||||||
let item_name = names.get(useitem.item).unwrap();
|
let item_name = names.get(useitem.item).unwrap();
|
||||||
|
@ -31,6 +31,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
ReadStorage<'a, MeleeWeapon>,
|
ReadStorage<'a, MeleeWeapon>,
|
||||||
ReadStorage<'a, Wearable>,
|
ReadStorage<'a, Wearable>,
|
||||||
ReadStorage<'a, NaturalAttackDefense>,
|
ReadStorage<'a, NaturalAttackDefense>,
|
||||||
|
ReadExpect<'a, Entity>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
@ -51,6 +52,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
meleeweapons,
|
meleeweapons,
|
||||||
wearables,
|
wearables,
|
||||||
natural,
|
natural,
|
||||||
|
player_entity,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
for (entity, wants_melee, name, attacker_attributes, attacker_skills, attacker_pools) in (
|
for (entity, wants_melee, name, attacker_attributes, attacker_skills, attacker_pools) in (
|
||||||
@ -154,7 +156,12 @@ impl<'a> System<'a> for MeleeCombatSystem {
|
|||||||
+ skill_damage_bonus
|
+ skill_damage_bonus
|
||||||
+ weapon_damage_bonus,
|
+ weapon_damage_bonus,
|
||||||
);
|
);
|
||||||
SufferDamage::new_damage(&mut inflict_damage, wants_melee.target, damage);
|
SufferDamage::new_damage(
|
||||||
|
&mut inflict_damage,
|
||||||
|
wants_melee.target,
|
||||||
|
damage,
|
||||||
|
entity == *player_entity,
|
||||||
|
);
|
||||||
log.append(format!(
|
log.append(format!(
|
||||||
"{} hits {} for {} hp.",
|
"{} hits {} for {} hp.",
|
||||||
&name.name, &target_name.name, damage
|
&name.name, &target_name.name, damage
|
||||||
|
@ -77,6 +77,7 @@ impl<'a> System<'a> for TriggerSystem {
|
|||||||
&mut inflict_damage,
|
&mut inflict_damage,
|
||||||
entity,
|
entity,
|
||||||
damage.damage,
|
damage.damage,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user