mp regeneration

using nethack calcs as a placeholder for now
This commit is contained in:
Llywelwyn 2023-08-22 19:07:50 +01:00
parent c46e302274
commit 4118783597
6 changed files with 64 additions and 11 deletions

View file

@ -1,4 +1,6 @@
use crate::{gamelog, Clock, Player, Pools, Position, TakingTurn};
use crate::{
gamelog, gui::Class, Attributes, Clock, HasClass, Player, Pools, Position, RandomNumberGenerator, TakingTurn,
};
use specs::prelude::*;
pub struct RegenSystem {}
@ -6,6 +8,12 @@ pub struct RegenSystem {}
const MONSTER_HP_REGEN_TURN: i32 = 20;
const MONSTER_HP_REGEN_PER_TICK: i32 = 1;
const WIZARD_MP_REGEN_MOD: i32 = 3;
const NONWIZARD_MP_REGEN_MOD: i32 = 4;
const MP_REGEN_BASE: i32 = 38;
const MP_REGEN_DIVISOR: i32 = 6;
const MIN_MP_REGEN_PER_TURN: i32 = 1;
impl<'a> System<'a> for RegenSystem {
#[allow(clippy::type_complexity)]
type SystemData = (
@ -15,10 +23,13 @@ impl<'a> System<'a> for RegenSystem {
WriteStorage<'a, Pools>,
ReadStorage<'a, TakingTurn>,
ReadStorage<'a, Player>,
ReadStorage<'a, HasClass>,
ReadStorage<'a, Attributes>,
WriteExpect<'a, RandomNumberGenerator>,
);
fn run(&mut self, data: Self::SystemData) {
let (clock, entities, positions, mut pools, turns, player) = data;
let (clock, entities, positions, mut pools, turns, player, classes, attributes, mut rng) = data;
let mut clock_turn = false;
for (_e, _c, _t) in (&entities, &clock, &turns).join() {
clock_turn = true;
@ -26,18 +37,30 @@ impl<'a> System<'a> for RegenSystem {
if !clock_turn {
return;
}
// Monster HP regen
let current_turn = gamelog::get_event_count("turns");
if current_turn % MONSTER_HP_REGEN_TURN == 0 {
for (_e, _p, pool, _player) in (&entities, &positions, &mut pools, !&player).join() {
try_hp_regen_tick(pool, MONSTER_HP_REGEN_PER_TICK);
}
}
// Player HP regen
let level = gamelog::get_event_count("player_level");
if current_turn % get_player_hp_regen_turn(level) == 0 {
for (_e, _p, pool, _player) in (&entities, &positions, &mut pools, &player).join() {
try_hp_regen_tick(pool, get_player_hp_regen_per_tick(level));
}
}
// Both MP regen
for (e, _p, pool) in (&entities, &positions, &mut pools).join() {
let is_wizard = if let Some(class) = classes.get(e) { class.name == Class::Wizard } else { false };
let numerator = if is_wizard { WIZARD_MP_REGEN_MOD } else { NONWIZARD_MP_REGEN_MOD };
let multiplier: f32 = numerator as f32 / MP_REGEN_DIVISOR as f32;
let mp_regen_tick = ((MP_REGEN_BASE - pool.level) as f32 * multiplier) as i32;
if current_turn % mp_regen_tick == 0 {
try_mana_regen_tick(pool, rng.roll_dice(1, get_mana_regen_per_tick(e, &attributes)));
}
}
}
}
@ -60,3 +83,15 @@ fn get_player_hp_regen_per_tick(level: i32) -> i32 {
fn try_hp_regen_tick(pool: &mut Pools, amount: i32) {
pool.hit_points.current = i32::min(pool.hit_points.current + amount, pool.hit_points.max);
}
fn get_mana_regen_per_tick(e: Entity, attributes: &ReadStorage<Attributes>) -> i32 {
return if let Some(attributes) = attributes.get(e) {
((attributes.intelligence.bonus + attributes.wisdom.bonus) / 2) + MIN_MP_REGEN_PER_TURN
} else {
MIN_MP_REGEN_PER_TURN
};
}
fn try_mana_regen_tick(pool: &mut Pools, amount: i32) {
pool.mana.current = i32::min(pool.mana.current + amount, pool.mana.max);
}

View file

@ -190,6 +190,17 @@ pub struct Skills {
pub skills: HashMap<Skill, i32>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct KnownSpell {
pub display_name: String,
pub mana_cost: i32,
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct KnownSpells {
pub spells: Vec<KnownSpell>,
}
#[derive(Component, Debug, Serialize, Deserialize, Clone)]
pub struct Attributes {
pub strength: Attribute,

View file

@ -284,8 +284,8 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) {
.insert(
player,
Pools {
hit_points: Pool { current: 10 + attr_bonus(con), max: 10 + attr_bonus(con) },
mana: Pool { current: 2 + attr_bonus(int), max: 2 + attr_bonus(int) },
hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) },
mana: Pool { current: 1 + attr_bonus(int), max: 1 + attr_bonus(int) },
xp: 0,
level: 1,
bac: 10,

View file

@ -659,6 +659,7 @@ fn main() -> rltk::BError {
gs.ecs.register::<MultiAttack>();
gs.ecs.register::<ProvidesRemoveCurse>();
gs.ecs.register::<ProvidesIdentify>();
gs.ecs.register::<KnownSpells>();
gs.ecs.register::<ParticleLifetime>();
gs.ecs.register::<SpawnParticleSimple>();
gs.ecs.register::<SpawnParticleBurst>();

View file

@ -82,6 +82,7 @@ pub fn save_game(ecs: &mut World) {
InBackpack,
InflictsDamage,
Item,
KnownSpells,
LootTable,
MagicItem,
MagicMapper,
@ -209,6 +210,7 @@ pub fn load_game(ecs: &mut World) {
InBackpack,
InflictsDamage,
Item,
KnownSpells,
LootTable,
MagicItem,
MagicMapper,

View file

@ -1,7 +1,9 @@
use super::{
ai::NORMAL_SPEED, random_table::RandomTable, raws, Clock, Energy, EquipmentChanged, Faction, HungerClock,
HungerState, Map, Mind, Name, Player, Position, Rect, Renderable, SerializeMe, Skill, Skills, TileType, Viewshed,
ai::NORMAL_SPEED, random_table::RandomTable, raws, Attribute, Attributes, Clock, Energy, EquipmentChanged, Faction,
HungerClock, HungerState, Map, Mind, Name, Player, Pool, Pools, Position, Rect, Renderable, SerializeMe, Skill,
Skills, TileType, Viewshed,
};
use crate::gamesystem::*;
use rltk::{RandomNumberGenerator, RGB};
use specs::prelude::*;
use specs::saveload::{MarkedBuilder, SimpleMarker};
@ -13,7 +15,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
skills.skills.insert(Skill::Melee, 0);
skills.skills.insert(Skill::Defence, 0);
skills.skills.insert(Skill::Magic, 0);
let (int, con) = (10, 10);
// We only create the player once, so create the Clock here for counting turns too.
ecs.create_entity().with(Clock {}).with(Energy { current: 0, speed: NORMAL_SPEED }).build();
let player = ecs
@ -31,7 +33,8 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
.with(Viewshed { visible_tiles: Vec::new(), range: 12, dirty: true })
.with(Name { name: "you".to_string(), plural: "you".to_string() })
.with(HungerClock { state: HungerState::Satiated, duration: 1200 })
/*.with(Attributes {
.with(Attributes {
// These are overwritten with chargen later -- placeholders.
strength: Attribute { base: 10, modifiers: 0, bonus: 0 },
dexterity: Attribute { base: 10, modifiers: 0, bonus: 0 },
constitution: Attribute { base: 10, modifiers: 0, bonus: 0 },
@ -40,14 +43,15 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity {
charisma: Attribute { base: 10, modifiers: 0, bonus: 0 },
})
.with(Pools {
hit_points: Pool { current: 10 + attr_bonus(con), max: 10 + attr_bonus(con) },
mana: Pool { current: 2 + attr_bonus(int), max: 2 + attr_bonus(int) },
// These are overwritten with chargen later -- placeholders.
hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) },
mana: Pool { current: 1 + attr_bonus(int), max: 1 + attr_bonus(int) },
xp: 0,
level: 1,
bac: 10,
weight: 0.0,
god: false,
})*/
})
.with(EquipmentChanged {})
.with(skills)
.with(Energy { current: 0, speed: NORMAL_SPEED })