use crate::ai::AiPool;
use crate::bestiary;
use crate::items::ItemKind;
use crate::world::{Item, World};
#[derive(Clone, Copy, Debug)]
pub struct AttackOutcome {
pub hit: bool,
pub damage: i32,
pub critical: bool,
}
pub fn player_attacks(world: &mut World, ai: &mut AiPool, monster_idx: usize) -> AttackOutcome {
let monster_kind_idx = world.monsters[monster_idx].kind as usize;
let kind = bestiary::kind(monster_kind_idx);
let roll = (world.rng_next() % 20) as i64 + 1;
let (hit_kind, damage) = ai
.dispatch_combat(
world.player.skill as i64,
world.player.weapon_damage() as i64,
kind.evasion as i64,
kind.armor as i64,
roll,
)
.unwrap_or((0, 0));
if hit_kind == 0 {
return AttackOutcome {
hit: false,
damage: 0,
critical: false,
};
}
let damage = damage as i32;
let critical = hit_kind == 2;
let kind_name = kind.name;
let score = kind.score;
let new_hp = world.monsters[monster_idx].hp - damage;
if new_hp <= 0 {
let mx = world.monsters[monster_idx].x;
let my = world.monsters[monster_idx].y;
let drop_chance = kind.corpse_drop_chance;
world.monsters.swap_remove(monster_idx);
world.player.gold += score;
world.push_message(format!("You slay the {}.", kind_name));
if drop_chance > 0 {
let roll = (world.rng_next() % 100) as u8;
if roll < drop_chance {
world.items.push(Item {
kind: ItemKind::Corpse,
subtype: monster_kind_idx as u8,
x: mx,
y: my,
});
}
}
} else {
world.monsters[monster_idx].hp = new_hp;
let label = if critical { "critical hit" } else { "hit" };
world.push_message(format!(
"You {} the {} for {} damage.",
label, kind_name, damage
));
}
AttackOutcome {
hit: true,
damage,
critical,
}
}
pub fn monster_attacks_player(
world: &mut World,
ai: &mut AiPool,
monster_idx: usize,
) -> AttackOutcome {
let monster_kind_idx = world.monsters[monster_idx].kind as usize;
let kind = bestiary::kind(monster_kind_idx);
let roll = (world.rng_next() % 20) as i64 + 1;
let (hit_kind, damage) = ai
.dispatch_combat(
kind.skill as i64,
kind.damage as i64,
world.player.level as i64,
world.player.armor_value() as i64,
roll,
)
.unwrap_or((0, 0));
if hit_kind == 0 {
let name = kind.name;
world.push_message(format!("The {} misses.", name));
return AttackOutcome {
hit: false,
damage: 0,
critical: false,
};
}
let damage = damage as i32;
let critical = hit_kind == 2;
world.player.hp -= damage;
let name = kind.name;
let label = if critical { "crits" } else { "hits" };
world.push_message(format!("The {} {} you for {} damage.", name, label, damage));
AttackOutcome {
hit: true,
damage,
critical,
}
}