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, pub name: String, pub birth_date: Time, pub birth_location: Rc, pub profession: Profession, pub location: [usize; 2], pub agenda: Agenda, } impl Person { pub fn new(birth_date: Time, birth_location: Rc, 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 { 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") }, } } }