Sword-fighting

This commit is contained in:
Michael Smith 2021-10-27 00:02:09 +02:00
parent e85828fd33
commit b652bd512d

View File

@ -54,6 +54,8 @@ struct Object {
name: String,
blocks: bool,
alive: bool,
fighter: Option<Fighter>,
ai: Option<Ai>,
}
impl Object {
@ -66,6 +68,8 @@ impl Object {
name: name.into(),
blocks: blocks,
alive: false,
fighter: None,
ai: None,
}
}
@ -83,6 +87,12 @@ impl Object {
self.x = x;
self.y = y;
}
pub fn distance_to(&self, other: &Object) -> f32 {
let dx = other.x - self.x;
let dy = other.y - self.y;
((dx.pow(2) + dy.pow(2)) as f32).sqrt()
}
}
#[derive(Clone, Copy, Debug)]
@ -146,6 +156,15 @@ impl Rect {
}
}
// Combat related properties and methods (monster, player, NPC).
#[derive(Clone, Copy, Debug, PartialEq)]
struct Fighter {
max_hp: i32,
hp: i32,
defense: i32,
power: i32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum PlayerAction {
TookTurn,
@ -153,6 +172,11 @@ enum PlayerAction {
Exit,
}
#[derive(Clone, Debug, PartialEq)]
enum Ai {
Basic,
}
fn handle_keys(tcod: &mut Tcod, game: &Game, objects: &mut Vec<Object>) -> PlayerAction {
use tcod::input::Key;
use tcod::input::KeyCode::*;
@ -275,10 +299,26 @@ fn place_objects(room: Rect, map: &Map, objects: &mut Vec<Object>) {
if !is_blocked(x, y, map, objects) {
let mut monster = if rand::random::<f32>() < 0.8 {
// 80% chance of spawning an orc
Object::new(x, y, 'o', "orc", DESATURATED_GREEN, true)
let mut orc = Object::new(x, y, 'o', "orc", DESATURATED_GREEN, true);
orc.fighter = Some(Fighter {
max_hp: 10,
hp: 10,
defense: 0,
power: 3,
});
orc.ai = Some(Ai::Basic);
orc
} else {
// 20% chance of spawning a troll
Object::new(x, y, 'T', "troll", DARKER_GREEN, true)
let mut troll = Object::new(x, y, 'T', "troll", DARKER_GREEN, true);
troll.fighter = Some(Fighter {
max_hp: 16,
hp: 16,
defense: 1,
power: 4,
});
troll.ai = Some(Ai::Basic);
troll
};
monster.alive = true;
@ -327,6 +367,38 @@ fn player_move_or_attack(dx: i32, dy: i32, game: &Game, objects: &mut [Object])
}
}
fn move_towards(id: usize, target_x: i32, target_y: i32, map: &Map, objects: &mut [Object]) {
// Vector from this object to the target, and distance
let dx = target_x - objects[id].x;
let dy = target_y - objects[id].y;
let distance = ((dx.pow(2) + dy.pow(2)) as f32).sqrt();
// Normalize it to length 1 (preserving direction), then round it and
// convert it to integer so the movement is restricted to the map grid
let dx = (dx as f32 / distance).round() as i32;
let dy = (dy as f32 / distance).round() as i32;
move_by(id, dx, dy, map, objects);
}
fn ai_take_turn(monster_id: usize, tcod: &Tcod, game: &Game, objects: &mut [Object]) {
// A basic monster takes its turn. If you can see it, it can see you.
let (monster_x, monster_y) = objects[monster_id].pos();
if tcod.fov.is_in_fov(monster_x, monster_y) {
if objects[monster_id].distance_to(&objects[PLAYER]) >= 2.0 {
// Move towards player if far away
let (player_x, player_y) = objects[PLAYER].pos();
move_towards(monster_id, player_x, player_y, &game.map, objects);
} else if objects[PLAYER].fighter.map_or(false, |f| f.hp > 0) {
// Close enough, attach! (if the player is still alive.)
let monster = &objects[monster_id];
println!(
"The attack of the {} bounces off your shiny metal armor!",
monster.name
);
}
}
}
fn render_all(tcod: &mut Tcod, game: &mut Game, objects: &[Object], fov_recompute: bool) {
if fov_recompute {
let player = &objects[PLAYER];
@ -398,6 +470,12 @@ fn main() {
// Create player object
let mut player = Object::new(0, 0, '@', "player", WHITE, true);
player.alive = true;
player.fighter = Some(Fighter {
max_hp: 30,
hp: 30,
defense: 2,
power: 5,
});
// List of objects in the world
let mut objects = vec![player];
@ -437,10 +515,9 @@ fn main() {
// Let monsters take their turn
if objects[PLAYER].alive && player_action != PlayerAction::DidntTakeTurn {
for object in &objects {
// ONly if object is not player
if (object as *const _) != (&objects[PLAYER] as *const _) {
println!("The {} growls!", object.name);
for id in 0..objects.len() {
if objects[id].ai.is_some() {
ai_take_turn(id, &tcod, &game, &mut objects);
}
}
}