tavern_keeper/src/person.rs

127 lines
3.5 KiB
Rust

use std::{rc::Rc, fmt::Display};
use rand::prelude::*;
use crate::{time::Time, world::Town, generators::PersonNameGenerator, state::GameState, entity::Entity};
#[derive(Clone, Copy)]
pub enum Profession {
Peasant,
Adventurer,
Blacksmith,
}
#[derive(Clone, Copy)]
pub enum Agenda {
Idle(u32),
Traveling([usize; 2]),
}
#[derive(Clone)]
pub struct Person {
pub id: Option<u32>,
pub name: String,
pub birth_date: Time,
pub birth_location: Rc<Town>,
pub profession: Profession,
pub location: [usize; 2],
pub agenda: Agenda,
}
impl Person {
pub fn new(birth_date: Time, birth_location: Rc<Town>, location: [usize; 2]) -> Person {
Person {
id: None,
name: PersonNameGenerator::name(),
birth_date: birth_date,
birth_location: birth_location,
profession: Profession::Peasant,
location: location,
agenda: Agenda::Idle(0),
}
}
pub fn step(&mut self, state: &mut GameState) {
match &self.agenda {
Agenda::Idle(days) => {
// do nothing
if *days <= 0 {
// pick random destination
let mut rng = rand::thread_rng();
let dest = state.world.structures.keys().choose(&mut rng);
self.agenda = Agenda::Traveling(*dest.unwrap());
} else {
self.agenda = Agenda::Idle(days - 1);
}
},
Agenda::Traveling(destination) => {
// TDOO: A* pathfinding with terrain costs
// move towards destination
if self.location[0] < destination[0] {
self.location[0] += 1;
} else if self.location[0] > destination[0] {
self.location[0] -= 1;
}
if self.location[1] < destination[1] {
self.location[1] += 1;
} else if self.location[1] > destination[1] {
self.location[1] -= 1;
}
if self.location == *destination {
self.agenda = Agenda::Idle(10);
}
},
}
}
}
impl Display for Person {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
impl Entity for Person {
fn id(&self) -> Option<u32> {
self.id
}
fn set_id(&mut self, id: u32) {
self.id = Some(id);
}
}
#[cfg(test)]
mod tests {
use crate::world::{World, Structure};
use super::*;
#[test]
fn test_person_creation() {
let person = Person::new(Time { time: 0 }, Rc::new(Town::new()), [0, 0]);
assert_ne!(person.name, "");
}
#[test]
fn test_traveling() {
let mut person = Person::new(Time { time: 0 }, Rc::new(Town::new()), [0, 0]);
person.agenda = Agenda::Traveling([10, 0]);
person.step(&mut GameState::new(World::new(32)));
assert_eq!(person.location, [1, 0]);
}
#[test]
fn test_start_traveling() {
let mut person = Person::new(Time { time: 0 }, Rc::new(Town::new()), [0, 0]);
person.agenda = Agenda::Idle(0);
let mut state = GameState::new(World::new(32));
state.world.add_structure(10, 10, Structure::Town(Rc::new(Town::new())));
person.step(&mut state);
match &person.agenda {
Agenda::Traveling(_) => {},
_ => { panic!("Person should be traveling") },
}
}
}