diff --git a/src/ai/encumbrance_system.rs b/src/ai/encumbrance_system.rs index 2a4407c..5f39f3c 100644 --- a/src/ai/encumbrance_system.rs +++ b/src/ai/encumbrance_system.rs @@ -60,8 +60,7 @@ impl<'a> System<'a> for EncumbranceSystem { pool.weight = *weight; if let Some(attr) = attributes.get(*entity) { let carry_capacity_lbs = - (attr.strength.base + attr.strength.modifiers) * - CARRY_CAPACITY_PER_STRENGTH; + (attr.strength.base + attr.strength.bonuses) * CARRY_CAPACITY_PER_STRENGTH; if (pool.weight as i32) > 3 * carry_capacity_lbs { // Overloaded burdened diff --git a/src/ai/regen_system.rs b/src/ai/regen_system.rs index 1627b9d..a7ee874 100644 --- a/src/ai/regen_system.rs +++ b/src/ai/regen_system.rs @@ -121,7 +121,8 @@ fn try_hp_regen_tick(pool: &mut Pools, amount: i32) { fn get_mana_regen_per_tick(e: Entity, attributes: &ReadStorage) -> i32 { let regen = if let Some(attributes) = attributes.get(e) { - (attributes.intelligence.bonus + attributes.wisdom.bonus) / 2 + MIN_MP_REGEN_PER_TURN + (attributes.intelligence.modifier() + attributes.wisdom.modifier()) / 2 + + MIN_MP_REGEN_PER_TURN } else { MIN_MP_REGEN_PER_TURN }; diff --git a/src/components.rs b/src/components.rs index 4957362..5477d06 100644 --- a/src/components.rs +++ b/src/components.rs @@ -256,17 +256,35 @@ pub struct Pools { #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Attribute { pub base: i32, - pub modifiers: i32, - pub bonus: i32, + pub bonuses: i32, pub exercise: i32, } impl Attribute { + pub fn new(base: i32) -> Self { + Self { + base, + bonuses: 0, + exercise: 0, + } + } + // Raw attribute score. e.g. 10 base, + 4 from armour: 14 strength. + pub fn current(&self) -> i32 { + self.base + self.bonuses + } + // Attribute bonus. e.g. 14 strength = +2, 8 strength = -1 + pub fn modifier(&self) -> i32 { + crate::gamesystem::attr_bonus(self.current()) + } pub fn improve(&mut self) { - self.exercise += 1; + if self.exercise < 50 { + self.exercise += 1; + } } pub fn abuse(&mut self) { - self.exercise -= 1; + if self.exercise > -50 { + self.exercise -= 1; + } } } @@ -316,14 +334,31 @@ impl Attributes { pub const INT: i32 = 3; pub const WIS: i32 = 4; pub const CHA: i32 = 5; + pub fn default() -> Self { + Self { + strength: Attribute::new(10), + dexterity: Attribute::new(10), + constitution: Attribute::new(10), + intelligence: Attribute::new(10), + wisdom: Attribute::new(10), + charisma: Attribute::new(10), + } + } + pub fn with_stats(str: i32, dex: i32, con: i32, int: i32, wis: i32, cha: i32) -> Self { + Self { + strength: Attribute::new(str), + dexterity: Attribute::new(dex), + constitution: Attribute::new(con), + intelligence: Attribute::new(int), + wisdom: Attribute::new(wis), + charisma: Attribute::new(cha), + } + } pub fn exercise(&mut self, attr: i32, improve: bool) { match attr { Self::STR => { if improve { - console::log("Improving strength."); - console::log(format!("Value before: {}", self.strength.exercise)); self.strength.improve(); - console::log(format!("Value after: {}", self.strength.exercise)); } else { self.strength.abuse(); } diff --git a/src/effects/damage.rs b/src/effects/damage.rs index f689642..f9c9fd0 100644 --- a/src/effects/damage.rs +++ b/src/effects/damage.rs @@ -319,11 +319,11 @@ pub fn entity_death(ecs: &mut World, effect: &EffectSpawner, target: Entity) { let mut rng = ecs.write_resource::(); let hp_gained = hp_per_level( &mut rng, - source_attributes.constitution.base + source_attributes.constitution.modifiers + source_attributes.constitution.base + source_attributes.constitution.bonuses ); let mana_gained = mana_per_level( &mut rng, - source_attributes.intelligence.base + source_attributes.intelligence.modifiers + source_attributes.intelligence.base + source_attributes.intelligence.bonuses ); source_pools.hit_points.max += hp_gained; source_pools.hit_points.current += hp_gained; diff --git a/src/gui/character_creation.rs b/src/gui/character_creation.rs index a62e4a9..3c127b5 100644 --- a/src/gui/character_creation.rs +++ b/src/gui/character_creation.rs @@ -352,39 +352,7 @@ pub fn setup_player_class(ecs: &mut World, class: Class, ancestry: Ancestry) { let mut attributes = ecs.write_storage::(); let (str, dex, con, int, wis, cha) = get_attribute_rolls(&mut rng, class, ancestry); attributes - .insert(player, Attributes { - strength: Attribute { - base: str, - modifiers: 0, - bonus: attr_bonus(str), - exercise: 0, - }, - dexterity: Attribute { - base: dex, - modifiers: 0, - bonus: attr_bonus(dex), - exercise: 0, - }, - constitution: Attribute { - base: con, - modifiers: 0, - bonus: attr_bonus(con), - exercise: 0, - }, - intelligence: Attribute { - base: int, - modifiers: 0, - bonus: attr_bonus(int), - exercise: 0, - }, - wisdom: Attribute { base: wis, modifiers: 0, bonus: attr_bonus(wis), exercise: 0 }, - charisma: Attribute { - base: cha, - modifiers: 0, - bonus: attr_bonus(cha), - exercise: 0, - }, - }) + .insert(player, Attributes::with_stats(str, dex, con, int, wis, cha)) .expect("Unable to insert attributes component"); let mut pools = ecs.write_storage::(); diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 4d719ff..22afdce 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -193,7 +193,7 @@ pub fn draw_ui2( } } let armour_class = - stats.bac - attributes.dexterity.bonus / 2 - skill_ac_bonus - armour_ac_bonus; + stats.bac - attributes.dexterity.modifier() / 2 - skill_ac_bonus - armour_ac_bonus; draw.text(&font, "AC").position(x, row1).color(Color::PINK).size(FONTSIZE); x = draw.last_text_bounds().max_x(); draw.text(&font, &format!("{}", armour_class)).position(x, row1).size(FONTSIZE); @@ -340,7 +340,7 @@ pub fn draw_ui2( &format!( "[{:.1}/{} lbs]", stats.weight, - (attributes.strength.base + attributes.strength.modifiers) * + (attributes.strength.base + attributes.strength.bonuses) * CARRY_CAPACITY_PER_STRENGTH ) ) @@ -405,7 +405,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { } } let armour_class = - stats.bac - attributes.dexterity.bonus / 2 - skill_ac_bonus - armour_ac_bonus; + stats.bac - attributes.dexterity.modifier() / 2 - skill_ac_bonus - armour_ac_bonus; ctx.print_color(26 * TEXT_FONT_MOD, 53, RGB::named(PINK), RGB::named(BLACK), "AC"); ctx.print_color(28 * TEXT_FONT_MOD, 53, RGB::named(WHITE), RGB::named(BLACK), armour_class); // Draw level @@ -607,7 +607,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { &format!( "[{:.1}/{} lbs]", stats.weight, - (attributes.strength.base + attributes.strength.modifiers) * + (attributes.strength.base + attributes.strength.bonuses) * CARRY_CAPACITY_PER_STRENGTH ) ); diff --git a/src/gui/tooltip.rs b/src/gui/tooltip.rs index 3f2f37b..04c9898 100644 --- a/src/gui/tooltip.rs +++ b/src/gui/tooltip.rs @@ -118,18 +118,18 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut BTerm, xy: Option<(i32, i32)>) { let attr = attributes.get(entity); if let Some(a) = attr { let mut s = "".to_string(); - if a.strength.bonus < -2 { s += "weak "}; - if a.strength.bonus > 2 { s += "strong "}; - if a.dexterity.bonus < -2 { s += "clumsy "}; - if a.dexterity.bonus > 2 { s += "agile "}; - if a.constitution.bonus < -2 { s += "frail "}; - if a.constitution.bonus > 2 { s += "hardy "}; - if a.intelligence.bonus < -2 { s += "dim "}; - if a.intelligence.bonus > 2 { s += "smart "}; - if a.wisdom.bonus < -2 { s += "unwise "}; - if a.wisdom.bonus > 2 { s += "wisened "}; - if a.charisma.bonus < -2 { s += "ugly"}; - if a.charisma.bonus > 2 { s += "attractive"}; + if a.strength.modifier() < -2 { s += "weak "}; + if a.strength.modifier() > 2 { s += "strong "}; + if a.dexterity.modifier() < -2 { s += "clumsy "}; + if a.dexterity.modifier() > 2 { s += "agile "}; + if a.constitution.modifier() < -2 { s += "frail "}; + if a.constitution.modifier() > 2 { s += "hardy "}; + if a.intelligence.modifier() < -2 { s += "dim "}; + if a.intelligence.modifier() > 2 { s += "smart "}; + if a.wisdom.modifier() < -2 { s += "unwise "}; + if a.wisdom.modifier() > 2 { s += "wisened "}; + if a.charisma.modifier() < -2 { s += "ugly"}; + if a.charisma.modifier() > 2 { s += "attractive"}; if !s.is_empty() { if s.ends_with(" ") { s.pop(); diff --git a/src/melee_combat_system.rs b/src/melee_combat_system.rs index cc63807..36eb670 100644 --- a/src/melee_combat_system.rs +++ b/src/melee_combat_system.rs @@ -149,7 +149,7 @@ impl<'a> System<'a> for MeleeCombatSystem { let attack_verb = attack.1; // Get all offensive bonuses let d20 = rng.roll_dice(1, 20); - let attribute_hit_bonus = attacker_attributes.dexterity.bonus; + let attribute_hit_bonus = attacker_attributes.dexterity.modifier(); let skill_hit_bonus = gamesystem::skill_bonus(Skill::Melee, &*attacker_skills); let mut equipment_hit_bonus = weapon_info.hit_bonus; for (wielded, to_hit) in (&equipped, &to_hit).join() { @@ -187,7 +187,7 @@ impl<'a> System<'a> for MeleeCombatSystem { // Get armour class let bac = target_pools.bac; - let attribute_ac_bonus = target_attributes.dexterity.bonus / 2; + let attribute_ac_bonus = target_attributes.dexterity.modifier() / 2; let skill_ac_bonus = gamesystem::skill_bonus(Skill::Defence, &*target_skills); let mut armour_ac_bonus = 0; for (wielded, ac) in (&equipped, &ac).join() { @@ -245,19 +245,19 @@ impl<'a> System<'a> for MeleeCombatSystem { let mut attribute_damage_bonus = weapon_info.damage_bonus; match weapon_info.attribute { WeaponAttribute::Dexterity => { - attribute_damage_bonus += attacker_attributes.dexterity.bonus; + attribute_damage_bonus += attacker_attributes.dexterity.modifier(); } WeaponAttribute::Strength => { - attribute_damage_bonus += attacker_attributes.strength.bonus; + attribute_damage_bonus += attacker_attributes.strength.modifier(); } WeaponAttribute::Finesse => { if - attacker_attributes.dexterity.bonus > - attacker_attributes.strength.bonus + attacker_attributes.dexterity.modifier() > + attacker_attributes.strength.modifier() { - attribute_damage_bonus += attacker_attributes.dexterity.bonus; + attribute_damage_bonus += attacker_attributes.dexterity.modifier(); } else { - attribute_damage_bonus += attacker_attributes.strength.bonus; + attribute_damage_bonus += attacker_attributes.strength.modifier(); } } } diff --git a/src/morgue.rs b/src/morgue.rs index fcaa4a8..1363ab9 100644 --- a/src/morgue.rs +++ b/src/morgue.rs @@ -129,19 +129,19 @@ fn draw_tombstone(ecs: &World, len: usize) -> String { pool.mana.max, "", "", - attr.strength.base + attr.strength.modifiers, - attr.strength.bonus, - attr.constitution.base + attr.constitution.modifiers, - attr.constitution.bonus, - attr.wisdom.base + attr.wisdom.modifiers, - attr.wisdom.bonus, + attr.strength.base + attr.strength.bonuses, + attr.strength.modifier(), + attr.constitution.base + attr.constitution.bonuses, + attr.constitution.modifier(), + attr.wisdom.base + attr.wisdom.bonuses, + attr.wisdom.modifier(), "", - attr.dexterity.base + attr.dexterity.modifiers, - attr.dexterity.bonus, - attr.intelligence.base + attr.intelligence.modifiers, - attr.intelligence.bonus, - attr.charisma.base + attr.charisma.modifiers, - attr.charisma.bonus, + attr.dexterity.base + attr.dexterity.bonuses, + attr.dexterity.modifier(), + attr.intelligence.base + attr.intelligence.bonuses, + attr.intelligence.modifier(), + attr.charisma.base + attr.charisma.bonuses, + attr.charisma.modifier(), "", "", map.name, diff --git a/src/player.rs b/src/player.rs index c8af2cc..2677c95 100644 --- a/src/player.rs +++ b/src/player.rs @@ -102,7 +102,7 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { .append("is blocked.") .log(); } - } else if rng.roll_dice(1, 6) + attributes.strength.bonus < 2 { + } else if rng.roll_dice(1, 6) + attributes.strength.modifier() < 2 { if let Some(name) = names.get(potential_target) { gamelog::Logger ::new() @@ -208,7 +208,7 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState { if let Some(door) = door { if door.open == false { let renderables = ecs.read_storage::(); - if rng.roll_dice(1, 6) + attributes.strength.bonus < 2 { + if rng.roll_dice(1, 6) + attributes.strength.modifier() < 2 { if let Some(name) = names.get(potential_target) { gamelog::Logger ::new() @@ -345,7 +345,7 @@ pub fn kick(i: i32, j: i32, ecs: &mut World) -> RunState { Targets::Entity { target: potential_target } ); // ~33% chance of breaking it down + str - if rng.roll_dice(1, 10) + attributes.strength.bonus > 6 { + if rng.roll_dice(1, 10) + attributes.strength.modifier() > 6 { gamelog::Logger ::new() .append("As you kick the") diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index 923286a..5cc8735 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -440,66 +440,29 @@ pub fn spawn_named_mob( } // Setup combat stats - let mut attr = Attributes { - strength: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - dexterity: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - constitution: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - intelligence: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - wisdom: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - charisma: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - }; + let mut attr = Attributes::default(); let mut mob_con = 10; let mut mob_int = 10; if let Some(attributes) = &mob_template.attributes { if let Some(str) = attributes.str { - attr.strength = Attribute { - base: str, - modifiers: 0, - bonus: attr_bonus(str), - exercise: 0, - }; + attr.strength = Attribute::new(str); } if let Some(dex) = attributes.dex { - attr.strength = Attribute { - base: dex, - modifiers: 0, - bonus: attr_bonus(dex), - exercise: 0, - }; + attr.strength = Attribute::new(dex); } if let Some(con) = attributes.con { - attr.constitution = Attribute { - base: con, - modifiers: 0, - bonus: attr_bonus(con), - exercise: 0, - }; + attr.constitution = Attribute::new(con); mob_con = con; } if let Some(int) = attributes.int { - attr.intelligence = Attribute { - base: int, - modifiers: 0, - bonus: attr_bonus(int), - exercise: 0, - }; + attr.intelligence = Attribute::new(int); mob_int = int; } if let Some(wis) = attributes.wis { - attr.wisdom = Attribute { - base: wis, - modifiers: 0, - bonus: attr_bonus(wis), - exercise: 0, - }; + attr.wisdom = Attribute::new(wis); } if let Some(cha) = attributes.cha { - attr.charisma = Attribute { - base: cha, - modifiers: 0, - bonus: attr_bonus(cha), - exercise: 0, - }; + attr.charisma = Attribute::new(cha); } } eb = eb.with(attr); diff --git a/src/spawner.rs b/src/spawner.rs index 44a3b04..1a5b64c 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -77,15 +77,7 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { }) .with(Name { name: "you".to_string(), plural: "you".to_string() }) .with(HungerClock { state: HungerState::Satiated, duration: 1200 }) - .with(Attributes { - // These are overwritten with chargen later -- placeholders. - strength: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - dexterity: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - constitution: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - intelligence: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - wisdom: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - charisma: Attribute { base: 10, modifiers: 0, bonus: 0, exercise: 0 }, - }) + .with(Attributes::default()) .with(Pools { // These are overwritten with chargen later -- placeholders. hit_points: Pool { current: 8 + attr_bonus(con), max: 8 + attr_bonus(con) },