tavern_keeper/src/creature.rs

134 lines
4.0 KiB
Rust

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<Box<dyn Action>> {
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()
},
}
}
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") },
}
}
}