use std::{fmt::Display}; use rand::prelude::*; use crate::{time::Time, world::{World}, generators::PersonNameGenerator, state::{GameState, Action}, entity::{Entity, Location}}; #[derive(Clone, Copy)] pub enum Profession { Peasant, } #[derive(Clone, Copy)] pub enum Agenda { Idle(u32), Traveling(Location), } #[derive(Clone)] pub struct Creature { pub entity: Entity, pub name: String, pub birth_date: Time, pub profession: Profession, pub agenda: Agenda, } impl Creature { pub fn new(birth_date: Time, location: Location) -> Creature { Creature { entity: Entity { id: 0, loc: location }, name: PersonNameGenerator::name(), birth_date: birth_date, profession: Profession::Peasant, agenda: Agenda::Idle(0), } } pub fn step(&mut self, world: &World) -> Vec> { match &self.agenda { Agenda::Idle(days) => { // do nothing if *days <= 0 { // pick random destination let mut rng = rand::thread_rng(); let dest = world.sites.keys().choose(&mut rng); self.agenda = Agenda::Traveling(*dest.unwrap()); } else { self.agenda = Agenda::Idle(days - 1); } Vec::new() }, Agenda::Traveling(destination) => { // TDOO: A* pathfinding with terrain costs // move towards destination if self.entity.loc.x < destination.x { self.entity.loc.x += 1; } else if self.entity.loc.x > destination.x { self.entity.loc.x -= 1; } if self.entity.loc.y < destination.y { self.entity.loc.y += 1; } else if self.entity.loc.y > destination.y { self.entity.loc.y -= 1; } if self.entity.loc == *destination { self.agenda = Agenda::Idle(10); } Vec::new() }, } } #[allow(dead_code)] pub fn set_agenda(&mut self, agenda: Agenda) { self.agenda = agenda; } pub fn say_agenda(&self, state: & GameState) -> String { match &self.agenda { Agenda::Idle(days) => format!("I'll stay here for {} days", days), Agenda::Traveling(destination) => { let dest_site = state.world.get_site_at(*destination); match dest_site { Some(site) => { return format!("I'm traveling to {}", site); }, None => return format!("I'm traveling to an unknown location"), } } } } } impl Display for Creature { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name) } } #[cfg(test)] mod tests { use crate::{world::{World}, site::{Site, Town, Structure}}; use super::*; #[test] fn test_person_creation() { let person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0}); assert_ne!(person.name, ""); } #[test] fn test_traveling() { let mut person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0}); person.agenda = Agenda::Traveling(Location{x: 10, y: 0}); person.step(&World::new(32)); assert_eq!(person.entity.loc, Location{x: 1, y: 0}); } #[test] fn test_start_traveling() { let mut person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0}); person.agenda = Agenda::Idle(0); let mut world = World::new(32); world.add_site(Site{ entity: Entity { id: 0, loc: Location{x: 10, y: 10} }, structure: Structure::Town(Town::new()), }); person.step(&world); match &person.agenda { Agenda::Traveling(_) => {}, _ => { panic!("Person should be traveling") }, } } }