improve combat system

This commit is contained in:
Joachim Lusiardi 2024-10-20 22:12:28 +02:00
parent efc4cdd363
commit cefb0cc5f2
6 changed files with 89 additions and 45 deletions

View File

@ -49,8 +49,10 @@ impl Game {
fn player_reached_goal(&mut self) -> bool {
match self.next_element(0, 0) {
None => {}
Some(a) => if a == StructureElement::End {
return true
Some(a) => {
if a == StructureElement::End {
return true;
}
}
};
false
@ -153,6 +155,7 @@ impl Game {
.discover(&Position::new(player_level, new_x, new_y));
(-dx, -dy)
}
pub fn player_fights_monster(&mut self) -> bool {
let player_pos = &self.player.get_immutable_position();
let player_level = player_pos.get_level();
@ -162,12 +165,21 @@ impl Game {
None => {}
Some(m) => {
// TODO fight the monster
self.player.change_life(-1);
m.decrease_life(1);
self.messages
.insert(0, format!("{} hits you.", m.get_name()).to_string());
self.messages
.insert(0, format!("you hit {}.", m.get_name()).to_string());
let monster_dmg = m.damage() as i16;
let player_dmg = self.player.damage();
self.player.change_life(-monster_dmg);
m.decrease_life(player_dmg);
// inform player
self.messages.insert(
0,
format!("{} hits you for {} damage.", m.get_name(), monster_dmg).to_string(),
);
self.messages.insert(
0,
format!("you hit {} for {} damage.", m.get_name(), player_dmg).to_string(),
);
// monster died, player gains experience
if m.is_dead() {
self.player.gain_experience(m.get_experience_gain());

View File

@ -48,11 +48,7 @@ impl Level {
&mut self,
x: i16,
y: i16,
) -> (
Option<StructureElement>,
PossibleMonster,
PossibleArtifact
) {
) -> (Option<StructureElement>, PossibleMonster, PossibleArtifact) {
if x < 0 || y < 0 {
return (None, None, None);
}
@ -151,15 +147,29 @@ impl Level {
if player.get_immutable_position().get_x() == new_x
&& player.get_immutable_position().get_y() == new_y
{
self.monsters[index].decrease_life(1);
player.change_life(-1);
// TODO handle fight between monster and player
let monster_dmg = self.monsters[index].damage() as i16;
let player_dmg = player.damage();
self.monsters[index].decrease_life(player_dmg);
player.change_life(-monster_dmg);
messages.insert(
0,
format!("{} hits you.", self.monsters[index].get_name()).to_string(),
format!(
"{} hits you for {} damage.",
self.monsters[index].get_name(),
monster_dmg
)
.to_string(),
);
messages.insert(
0,
format!("you hit {}.", self.monsters[index].get_name()).to_string(),
format!(
"you hit {} for {} damage.",
self.monsters[index].get_name(),
player_dmg
)
.to_string(),
);
// if the attack did not kill the opponent, back down
if !player.is_dead() {

View File

@ -11,7 +11,7 @@ use rand::Rng;
use crate::artifacts::{Artifact, Chest, Potion};
use crate::level::{Level, StructureElement};
use crate::monster::{Monster, Orc, Rat};
use crate::monster::{Monster, Orc, Rat, Snake};
use crate::position::Position;
const ROOMS_VERTICAL: usize = 7;
@ -301,11 +301,16 @@ impl LevelGenerator {
let t_y = top + room.offset_y + rng.gen_range(0..room.height);
// TODO randomize enemies here
match rng.gen_range(1..=100) {
1..=50 => {
1..=30 => {
enemies.push(Box::new(Orc::new_with_position(Position::new(
self.level, t_x, t_y,
))));
}
31..=60 => {
enemies.push(Box::new(Snake::new_with_position(Position::new(
self.level, t_x, t_y,
))));
}
_ => {
enemies.push(Box::new(Rat::new_with_position(Position::new(
self.level, t_x, t_y,

View File

@ -35,7 +35,7 @@ pub const FRAME_LENGTH: u64 = 100;
//
fn main() -> Result<()> {
let mut game = Game::new(Player::new(realname().as_str(), 10));
let mut game = Game::new(Player::new(realname().as_str(), 30));
stdout().execute(EnterAlternateScreen)?;
enable_raw_mode()?;
@ -108,7 +108,7 @@ fn main() -> Result<()> {
game.get_player().get_max_life(),
game.get_player().get_experience(),
game.get_player().get_gold(),
game.get_player().get_immutable_position().get_level()
game.get_player().get_immutable_position().get_level()+1
))
.block(block)
.wrap(Wrap { trim: true }),

View File

@ -1,3 +1,6 @@
use std::ops::RangeInclusive;
use rand::Rng;
use ratatui::prelude::Color;
use crate::position::{HasPosition, Position};
@ -12,10 +15,21 @@ pub trait Monster: HasPosition {
fn get_ticks_between_steps(&self) -> u128;
#[cfg(test)]
fn get_life(&self) -> usize;
fn damage(&self) -> usize;
}
macro_rules! default_monster {
($($t:ty),+ $(,)?) => ($(
macro_rules! create_monster {
($($t:ident),+ $(,)?) => ($(
pub struct $t {
name: String,
life: usize,
position: Position,
symbol: String,
color: Color,
experience_gain: usize,
ticks_between_steps: u128,
damage_range: RangeInclusive<usize>,
}
impl Monster for $t {
fn get_name(&self) -> &str { &self.name }
fn is_dead(&self) -> bool { self.life <= 0 }
@ -25,6 +39,7 @@ macro_rules! default_monster {
self.life = self.life.saturating_sub(by);
}
fn get_ticks_between_steps(&self) -> u128 { self.ticks_between_steps }
fn damage(&self) -> usize { rand::thread_rng().gen_range(self.damage_range.clone()) }
#[cfg(test)]
fn get_life(&self) -> usize { self.life }
@ -40,16 +55,6 @@ macro_rules! default_monster {
)+)
}
pub struct Rat {
name: String,
life: usize,
position: Position,
symbol: String,
color: Color,
experience_gain: usize,
ticks_between_steps: u128,
}
impl Rat {
pub fn new_with_position(position: Position) -> Self {
Self {
@ -60,20 +65,11 @@ impl Rat {
color: Color::Black,
experience_gain: 5,
ticks_between_steps: 5,
damage_range: 1..=2,
}
}
}
default_monster!(Rat);
pub struct Orc {
name: String,
life: usize,
position: Position,
symbol: String,
color: Color,
experience_gain: usize,
ticks_between_steps: u128,
}
create_monster!(Rat);
impl Orc {
pub fn new_with_position(position: Position) -> Self {
@ -85,11 +81,27 @@ impl Orc {
color: Color::DarkGray,
experience_gain: 10,
ticks_between_steps: 10,
damage_range: 2..=3,
}
}
}
create_monster!(Orc);
default_monster!(Orc);
impl Snake {
pub fn new_with_position(position: Position) -> Self {
Self {
name: "snake".to_string(),
life: 3,
position,
symbol: String::from("S"),
color: Color::DarkGray,
experience_gain: 10,
ticks_between_steps: 20,
damage_range: 1..=4,
}
}
}
create_monster!(Snake);
#[test]
fn monsters_can_move() {

View File

@ -1,3 +1,4 @@
use rand::Rng;
use std::cmp::{max, min};
use crate::position::{HasPosition, Position};
@ -60,6 +61,10 @@ impl Player {
pub fn get_experience(&self) -> usize {
self.experience
}
pub fn damage(&self) -> usize {
rand::thread_rng().gen_range(1..4)
}
}
impl HasPosition for Player {