removes monster to-hit bonus from player

This commit is contained in:
Llywelwyn 2023-08-22 13:11:21 +01:00
parent f55f4504db
commit bd90c3f760
8 changed files with 41 additions and 12 deletions

View file

@ -192,7 +192,7 @@
"weight": 6, "weight": 6,
"value": 10, "value": 10,
"flags": ["EQUIP_SHIELD"], "flags": ["EQUIP_SHIELD"],
"effects": { "ac": "2" } "effects": { "ac": "2", "to_hit": "-1" }
}, },
{ {
"id": "equip_largeshield", "id": "equip_largeshield",
@ -201,7 +201,7 @@
"weight": 12, "weight": 12,
"value": 35, "value": 35,
"flags": ["EQUIP_SHIELD"], "flags": ["EQUIP_SHIELD"],
"effects": { "ac": "3" } "effects": { "ac": "3", "to_hit": "-2" }
}, },
{ {
"id": "equip_body_weakleather", "id": "equip_body_weakleather",

View file

@ -316,6 +316,11 @@ pub struct ArmourClassBonus {
pub amount: i32, pub amount: i32,
} }
#[derive(Component, ConvertSaveload, Clone)]
pub struct ToHitBonus {
pub amount: i32,
}
#[derive(Component, Serialize, Deserialize, Clone)] #[derive(Component, Serialize, Deserialize, Clone)]
pub struct Equippable { pub struct Equippable {
pub slot: EquipmentSlot, pub slot: EquipmentSlot,

View file

@ -17,7 +17,7 @@ pub fn hp_per_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32) ->
#[allow(dead_code)] #[allow(dead_code)]
/// Returns a total HP roll for a player, based on a given constitution score and level. /// Returns a total HP roll for a player, based on a given constitution score and level.
pub fn player_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 { pub fn player_hp_at_level(rng: &mut rltk::RandomNumberGenerator, constitution: i32, level: i32) -> i32 {
let mut total = 10 + attr_bonus(constitution); let mut total = 8 + attr_bonus(constitution);
for _i in 0..level { for _i in 0..level {
total += hp_per_level(rng, constitution); total += hp_per_level(rng, constitution);
} }

View file

@ -489,7 +489,7 @@ pub fn obfuscate_name_ecs(ecs: &World, item: Entity) -> (String, String) {
if has_beatitude.known { if has_beatitude.known {
let prefix = match has_beatitude.buc { let prefix = match has_beatitude.buc {
BUC::Cursed => Some("cursed "), BUC::Cursed => Some("cursed "),
BUC::Uncursed => None, BUC::Uncursed => Some("uncursed "),
BUC::Blessed => Some("blessed "), BUC::Blessed => Some("blessed "),
}; };
if prefix.is_some() { if prefix.is_some() {

View file

@ -611,6 +611,7 @@ fn main() -> rltk::BError {
gs.ecs.register::<MeleeWeapon>(); gs.ecs.register::<MeleeWeapon>();
gs.ecs.register::<NaturalAttacks>(); gs.ecs.register::<NaturalAttacks>();
gs.ecs.register::<ArmourClassBonus>(); gs.ecs.register::<ArmourClassBonus>();
gs.ecs.register::<ToHitBonus>();
gs.ecs.register::<MoveMode>(); gs.ecs.register::<MoveMode>();
gs.ecs.register::<ProvidesHealing>(); gs.ecs.register::<ProvidesHealing>();
gs.ecs.register::<InflictsDamage>(); gs.ecs.register::<InflictsDamage>();

View file

@ -3,7 +3,8 @@ use super::{
gamelog, gamesystem, gamelog, gamesystem,
gui::renderable_colour, gui::renderable_colour,
ArmourClassBonus, Attributes, EquipmentSlot, Equipped, HungerClock, HungerState, MeleeWeapon, MultiAttack, Name, ArmourClassBonus, Attributes, EquipmentSlot, Equipped, HungerClock, HungerState, MeleeWeapon, MultiAttack, Name,
NaturalAttacks, ParticleBuilder, Pools, Position, Renderable, Skill, Skills, WantsToMelee, WeaponAttribute, NaturalAttacks, ParticleBuilder, Pools, Position, Renderable, Skill, Skills, ToHitBonus, WantsToMelee,
WeaponAttribute,
}; };
use rltk::prelude::*; use rltk::prelude::*;
use specs::prelude::*; use specs::prelude::*;
@ -26,6 +27,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
ReadStorage<'a, MeleeWeapon>, ReadStorage<'a, MeleeWeapon>,
ReadStorage<'a, NaturalAttacks>, ReadStorage<'a, NaturalAttacks>,
ReadStorage<'a, ArmourClassBonus>, ReadStorage<'a, ArmourClassBonus>,
ReadStorage<'a, ToHitBonus>,
ReadStorage<'a, HungerClock>, ReadStorage<'a, HungerClock>,
ReadStorage<'a, MultiAttack>, ReadStorage<'a, MultiAttack>,
WriteExpect<'a, rltk::RandomNumberGenerator>, WriteExpect<'a, rltk::RandomNumberGenerator>,
@ -47,6 +49,7 @@ impl<'a> System<'a> for MeleeCombatSystem {
melee_weapons, melee_weapons,
natural_attacks, natural_attacks,
ac, ac,
to_hit,
hunger_clock, hunger_clock,
multi_attackers, multi_attackers,
mut rng, mut rng,
@ -96,10 +99,10 @@ impl<'a> System<'a> for MeleeCombatSystem {
attacks.push(( attacks.push((
MeleeWeapon { MeleeWeapon {
attribute: WeaponAttribute::Strength, attribute: WeaponAttribute::Strength,
hit_bonus: 0,
damage_n_dice: 1, damage_n_dice: 1,
damage_die_type: 4, damage_die_type: 4,
damage_bonus: 0, damage_bonus: 0,
hit_bonus: 0,
}, },
"punches".to_string(), "punches".to_string(),
)); ));
@ -124,7 +127,12 @@ impl<'a> System<'a> for MeleeCombatSystem {
let d20 = rng.roll_dice(1, 20); let d20 = rng.roll_dice(1, 20);
let attribute_hit_bonus = attacker_attributes.dexterity.bonus; let attribute_hit_bonus = attacker_attributes.dexterity.bonus;
let skill_hit_bonus = gamesystem::skill_bonus(Skill::Melee, &*attacker_skills); let skill_hit_bonus = gamesystem::skill_bonus(Skill::Melee, &*attacker_skills);
let weapon_hit_bonus = weapon_info.hit_bonus; let mut equipment_hit_bonus = weapon_info.hit_bonus;
for (wielded, to_hit) in (&equipped, &to_hit).join() {
if wielded.owner == entity {
equipment_hit_bonus += to_hit.amount;
}
}
let mut status_hit_bonus = 0; let mut status_hit_bonus = 0;
let hc = hunger_clock.get(entity); let hc = hunger_clock.get(entity);
if let Some(hc) = hc { if let Some(hc) = hc {
@ -141,8 +149,13 @@ impl<'a> System<'a> for MeleeCombatSystem {
_ => {} _ => {}
} }
} }
let attacker_bonuses = // Total to-hit bonus
attacker_pools.level + attribute_hit_bonus + skill_hit_bonus + weapon_hit_bonus + status_hit_bonus; let attacker_bonuses = 1 // +1 for being in melee combat
+ attacker_pools.level // + level
+ attribute_hit_bonus // +- str/dex bonus depending on weapon used
+ skill_hit_bonus // +- relevant skill modifier
+ equipment_hit_bonus // +- any other to-hit modifiers from equipment
+ status_hit_bonus; // +- any to-hit modifiers from status effects
// Get armour class // Get armour class
let bac = target_pools.bac; let bac = target_pools.bac;
@ -164,17 +177,21 @@ impl<'a> System<'a> for MeleeCombatSystem {
armour_class_roll = -armour_class_roll; armour_class_roll = -armour_class_roll;
} }
let target_number = 10 + armour_class_roll + attacker_bonuses; // Monster attacks receive a +10 to-hit bonus against the player.
let monster_v_player_bonus = if wants_melee.target == *player_entity { 10 } else { 0 };
let target_number = monster_v_player_bonus + armour_class_roll + attacker_bonuses;
let target_name = names.get(wants_melee.target).unwrap(); let target_name = names.get(wants_melee.target).unwrap();
if COMBAT_LOGGING { if COMBAT_LOGGING {
rltk::console::log(format!( rltk::console::log(format!(
"ATTACKLOG: {} *{}* {}: rolled ({}) 1d20 vs. {} (10 + {}AC + {}to-hit)", "ATTACKLOG: {} *{}* {}: rolled ({}) 1d20 vs. {} ({} + {}AC + {}to-hit)",
&name.name, &name.name,
attack_verb, attack_verb,
&target_name.name, &target_name.name,
d20, d20,
target_number, target_number,
monster_v_player_bonus,
armour_class_roll, armour_class_roll,
attacker_bonuses attacker_bonuses
)); ));

View file

@ -29,6 +29,7 @@ macro_rules! apply_effects {
"aoe" => $eb = $eb.with(AOE { radius: effect.1.parse::<i32>().unwrap() }), "aoe" => $eb = $eb.with(AOE { radius: effect.1.parse::<i32>().unwrap() }),
"confusion" => $eb = $eb.with(Confusion { turns: effect.1.parse::<i32>().unwrap() }), "confusion" => $eb = $eb.with(Confusion { turns: effect.1.parse::<i32>().unwrap() }),
"ac" => $eb = $eb.with(ArmourClassBonus { amount: effect.1.parse::<i32>().unwrap() }), "ac" => $eb = $eb.with(ArmourClassBonus { amount: effect.1.parse::<i32>().unwrap() }),
"to_hit" => $eb = $eb.with(ToHitBonus { amount: effect.1.parse::<i32>().unwrap() }),
"particle_line" => $eb = $eb.with(parse_particle_line(&effect.1)), "particle_line" => $eb = $eb.with(parse_particle_line(&effect.1)),
"particle_burst" => $eb = $eb.with(parse_particle_burst(&effect.1)), "particle_burst" => $eb = $eb.with(parse_particle_burst(&effect.1)),
"particle" => $eb = $eb.with(parse_particle(&effect.1)), "particle" => $eb = $eb.with(parse_particle(&effect.1)),
@ -230,7 +231,7 @@ pub fn spawn_named_item(
) -> Option<Entity> { ) -> Option<Entity> {
if raws.item_index.contains_key(key) { if raws.item_index.contains_key(key) {
let item_template = &raws.raws.items[raws.item_index[key]]; let item_template = &raws.raws.items[raws.item_index[key]];
let dm = ecs.fetch::<crate::map::MasterDungeonMap>(); let mut dm = ecs.fetch_mut::<crate::map::MasterDungeonMap>();
let scroll_names = dm.scroll_map.clone(); let scroll_names = dm.scroll_map.clone();
let potion_names = dm.potion_map.clone(); let potion_names = dm.potion_map.clone();
let wand_names = dm.wand_map.clone(); let wand_names = dm.wand_map.clone();
@ -256,6 +257,9 @@ pub fn spawn_named_item(
} }
_ => false, _ => false,
}; };
if known_beatitude && !identified_items.contains(&item_template.name.name) {
dm.identified_items.insert(item_template.name.name.clone());
}
std::mem::drop(player_entity); std::mem::drop(player_entity);
std::mem::drop(dm); std::mem::drop(dm);
// -- DROP EVERYTHING THAT INVOLVES THE ECS BEFORE THIS POINT --- // -- DROP EVERYTHING THAT INVOLVES THE ECS BEFORE THIS POINT ---

View file

@ -110,6 +110,7 @@ pub fn save_game(ecs: &mut World) {
SpawnParticleSimple, SpawnParticleSimple,
TakingTurn, TakingTurn,
Telepath, Telepath,
ToHitBonus,
Viewshed, Viewshed,
Charges, Charges,
WantsToApproach, WantsToApproach,
@ -234,6 +235,7 @@ pub fn load_game(ecs: &mut World) {
SpawnParticleSimple, SpawnParticleSimple,
TakingTurn, TakingTurn,
Telepath, Telepath,
ToHitBonus,
Viewshed, Viewshed,
Charges, Charges,
WantsToApproach, WantsToApproach,