rust-rl/src/ai/regen_system.rs

107 lines
3.4 KiB
Rust

use crate::{
gamelog,
gui::Class,
Attributes,
Clock,
HasClass,
Player,
Pools,
Position,
RandomNumberGenerator,
TakingTurn,
};
use specs::prelude::*;
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 = (
ReadStorage<'a, Clock>,
Entities<'a>,
ReadStorage<'a, Position>,
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, classes, attributes, mut rng) = data;
let mut clock_turn = false;
for (_e, _c, _t) in (&entities, &clock, &turns).join() {
clock_turn = true;
}
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)));
}
}
}
}
fn get_player_hp_regen_turn(level: i32) -> i32 {
if level < 10 {
return 42 / (level + 2) + 1;
} else {
return 3;
}
}
fn get_player_hp_regen_per_tick(level: i32) -> i32 {
if level < 10 {
return 1;
} else {
return 2;
}
}
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 {
let regen = 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
};
return i32::max(regen, 1);
}
fn try_mana_regen_tick(pool: &mut Pools, amount: i32) {
pool.mana.current = i32::min(pool.mana.current + amount, pool.mana.max);
}