From 921fee2eccca007cb145400d022c6cb62dbb5a73 Mon Sep 17 00:00:00 2001 From: Llywelwyn Date: Thu, 21 Sep 2023 05:06:52 +0100 Subject: [PATCH] intrinsic speed + regeneration --- src/ai/energy_system.rs | 16 +++++++++++++++- src/ai/regen_system.rs | 33 +++++++++++++++++++++++++++++---- src/components.rs | 13 ++++++++++++- src/hunger_system.rs | 15 +++++++++++++-- src/main.rs | 1 + src/saveload_system.rs | 2 ++ src/spawner.rs | 8 ++++++-- 7 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/ai/energy_system.rs b/src/ai/energy_system.rs index 8ddbe4b..da62467 100644 --- a/src/ai/energy_system.rs +++ b/src/ai/energy_system.rs @@ -10,6 +10,7 @@ use crate::{ Map, TakingTurn, Confusion, + Intrinsics, }; use bracket_lib::prelude::*; use specs::prelude::*; @@ -36,6 +37,7 @@ impl<'a> System<'a> for EnergySystem { ReadStorage<'a, Name>, ReadExpect<'a, Point>, ReadStorage<'a, Confusion>, + ReadStorage<'a, Intrinsics>, ); fn run(&mut self, data: Self::SystemData) { @@ -53,6 +55,7 @@ impl<'a> System<'a> for EnergySystem { names, player_pos, confusion, + intrinsics, ) = data; // If not ticking, do nothing. if *runstate != RunState::Ticking { @@ -89,10 +92,12 @@ impl<'a> System<'a> for EnergySystem { ).join() { let burden_modifier = get_burden_modifier(&burdens, entity); let overmap_mod = get_overmap_modifier(&map); + let intrinsic_speed = get_intrinsic_speed(&intrinsics, entity); // Every entity has a POTENTIAL equal to their speed. let mut energy_potential: i32 = ((energy.speed as f32) * burden_modifier * - overmap_mod) as i32; + overmap_mod * + intrinsic_speed) as i32; // Increment current energy by NORMAL_SPEED for every // whole number of NORMAL_SPEEDS in their POTENTIAL. while energy_potential >= NORMAL_SPEED { @@ -162,3 +167,12 @@ fn cull_turn_by_distance(player_pos: &Point, pos: &Position) -> bool { } return false; } + +fn get_intrinsic_speed(intrinsics: &ReadStorage, entity: Entity) -> f32 { + if let Some(intrinsics) = intrinsics.get(entity) { + if intrinsics.list.contains(&crate::Intrinsic::Speed) { + return 4.0 / 3.0; + } + } + return 1.0; +} diff --git a/src/ai/regen_system.rs b/src/ai/regen_system.rs index b74f857..8114c4e 100644 --- a/src/ai/regen_system.rs +++ b/src/ai/regen_system.rs @@ -9,6 +9,7 @@ use crate::{ Position, RandomNumberGenerator, TakingTurn, + Intrinsics, }; use specs::prelude::*; use crate::data::events::*; @@ -36,10 +37,24 @@ impl<'a> System<'a> for RegenSystem { ReadStorage<'a, HasClass>, ReadStorage<'a, Attributes>, WriteExpect<'a, RandomNumberGenerator>, + ReadStorage<'a, Intrinsics>, + ReadExpect<'a, Entity>, ); fn run(&mut self, data: Self::SystemData) { - let (clock, entities, positions, mut pools, turns, player, classes, attributes, mut rng) = data; + let ( + clock, + entities, + positions, + mut pools, + turns, + player, + classes, + attributes, + mut rng, + intrinsics, + player_entity, + ) = data; let mut clock_turn = false; for (_e, _c, _t) in (&entities, &clock, &turns).join() { clock_turn = true; @@ -56,19 +71,29 @@ impl<'a> System<'a> for RegenSystem { } // Player HP regen let level = gamelog::get_event_count(EVENT::COUNT_LEVEL); - if current_turn % get_player_hp_regen_turn(level) == 0 { + if + current_turn % get_player_hp_regen_turn(level) == 0 || + intrinsics.get(*player_entity).unwrap().list.contains(&crate::Intrinsic::Regeneration) + { 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 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))); + try_mana_regen_tick( + pool, + rng.roll_dice(1, get_mana_regen_per_tick(e, &attributes)) + ); } } } diff --git a/src/components.rs b/src/components.rs index c2a2bb6..3a7a552 100644 --- a/src/components.rs +++ b/src/components.rs @@ -6,7 +6,7 @@ use specs::error::NoError; use specs::prelude::*; use specs::saveload::{ ConvertSaveload, Marker }; use specs_derive::*; -use std::collections::HashMap; +use std::collections::{ HashMap, HashSet }; // Serialization helper code. We need to implement ConvertSaveload for each type that contains an // Entity. @@ -418,6 +418,17 @@ impl HasDamageModifiers { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Intrinsic { + Regeneration, // Regenerate 1 HP on every tick + Speed, // 4/3x speed multiplier +} + +#[derive(Component, Serialize, Deserialize, Debug, Clone)] +pub struct Intrinsics { + pub list: HashSet, +} + #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct InflictsDamage { pub damage_type: DamageType, diff --git a/src/hunger_system.rs b/src/hunger_system.rs index 95d8dc3..7a1b0fd 100644 --- a/src/hunger_system.rs +++ b/src/hunger_system.rs @@ -6,6 +6,7 @@ use super::{ HungerState, TakingTurn, DamageType, + Intrinsics, }; use bracket_lib::prelude::*; use specs::prelude::*; @@ -53,10 +54,11 @@ impl<'a> System<'a> for HungerSystem { ReadExpect<'a, Entity>, ReadStorage<'a, Clock>, ReadStorage<'a, TakingTurn>, + ReadStorage<'a, Intrinsics>, ); fn run(&mut self, data: Self::SystemData) { - let (entities, mut hunger_clock, player_entity, turn_clock, turns) = data; + let (entities, mut hunger_clock, player_entity, turn_clock, turns, intrinsics) = data; // If the turn clock isn't taking a turn this tick, don't bother ticking hunger. let mut ticked = false; @@ -72,7 +74,16 @@ impl<'a> System<'a> for HungerSystem { if hunger_clock.duration >= MAX_SATIATION { hunger_clock.duration = MAX_SATIATION; } else { - hunger_clock.duration -= BASE_CLOCK_DECREMENT_PER_TURN; + let mut modifier = 0; + let intrinsic_regen = if let Some(i) = intrinsics.get(entity) { + i.list.contains(&crate::Intrinsic::Regeneration) + } else { + false + }; + if intrinsic_regen { + modifier += 1; + } + hunger_clock.duration -= BASE_CLOCK_DECREMENT_PER_TURN + modifier; } let initial_state = hunger_clock.state; hunger_clock.state = get_hunger_state(hunger_clock.duration); diff --git a/src/main.rs b/src/main.rs index 453d1fa..f82ebbd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -110,6 +110,7 @@ fn main() -> BError { gs.ecs.register::(); gs.ecs.register::(); gs.ecs.register::(); + gs.ecs.register::(); gs.ecs.register::>(); gs.ecs.register::(); gs.ecs.register::(); diff --git a/src/saveload_system.rs b/src/saveload_system.rs index 1b4ba57..894e4ff 100644 --- a/src/saveload_system.rs +++ b/src/saveload_system.rs @@ -95,6 +95,7 @@ pub fn save_game(ecs: &mut World) { IdentifiedItem, InBackpack, InflictsDamage, + Intrinsics, Item, KnownSpells, LootTable, @@ -226,6 +227,7 @@ pub fn load_game(ecs: &mut World) { IdentifiedItem, InBackpack, InflictsDamage, + Intrinsics, Item, KnownSpells, LootTable, diff --git a/src/spawner.rs b/src/spawner.rs index 7b62609..3fa673c 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -25,6 +25,8 @@ use super::{ Viewshed, BlocksTile, Bleeds, + HasDamageModifiers, + Intrinsics, }; use crate::data::entity; use crate::data::visuals::BLOODSTAIN_COLOUR; @@ -32,7 +34,7 @@ use crate::gamesystem::*; use bracket_lib::prelude::*; use specs::prelude::*; use specs::saveload::{ MarkedBuilder, SimpleMarker }; -use std::collections::HashMap; +use std::collections::{ HashMap, HashSet }; /// Spawns the player and returns his/her entity object. pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { @@ -86,7 +88,9 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { weight: 0.0, god: false, }) - .with(EquipmentChanged {}) + .with(HasDamageModifiers { modifiers: HashMap::new() }) + .with(Intrinsics { list: HashSet::new() }) + .with(EquipmentChanged {}) // To force re-calc of equipment bonuses. .with(skills) .with(Energy { current: 0, speed: entity::NORMAL_SPEED }) .marked::>()