tavern_keeper/src/state.rs

237 lines
7.1 KiB
Rust
Raw Normal View History

2022-12-31 07:54:18 +00:00
2022-12-31 14:22:44 +00:00
use std::collections::HashMap;
2022-12-31 07:54:18 +00:00
use rand::prelude::*;
2023-01-08 10:57:13 +00:00
use crate::entity::{Location, EntityId, Entity, EntityType};
2023-01-05 19:14:27 +00:00
use crate::creature::{Creature, Profession, CreatureGenerator};
2023-01-07 09:08:42 +00:00
use crate::item::{Item, ItemOwner};
2023-01-08 10:57:13 +00:00
use crate::site::{Town, Tavern, Site};
2022-12-31 07:54:18 +00:00
use crate::time::Time;
2023-01-04 16:52:58 +00:00
use crate::world::{World, Terrain};
2022-12-31 13:03:24 +00:00
use crate::events::{FoundTown, WorldGenesis, PersonGenesis, TavernBuilt};
2022-12-30 20:30:12 +00:00
pub struct GameState {
2022-12-31 07:54:18 +00:00
pub time: Time,
2022-12-30 20:30:12 +00:00
pub world: World,
2023-01-07 09:08:42 +00:00
pub creatures: HashMap<EntityId, Creature>,
pub items: HashMap<EntityId, Item>,
2022-12-31 13:03:24 +00:00
pub events: Vec<Box<Event>>,
2023-01-04 16:52:58 +00:00
pub tavern: Option<EntityId>,
2022-12-31 07:54:18 +00:00
}
pub struct Event {
pub time: Time,
2023-01-04 13:37:25 +00:00
pub effect: Box<dyn Action>,
2022-12-31 07:54:18 +00:00
}
2023-01-04 13:37:25 +00:00
pub trait Action {
// apply the effect to the game state
2022-12-31 07:54:18 +00:00
fn apply(&self, state: &mut GameState);
2023-01-04 13:37:25 +00:00
// description of the event that will be displayed in the event log
// TODO: thils needs a more complex return type.
// A notable event needs to be related to entities
2022-12-31 07:54:18 +00:00
fn description(&self) -> String;
2023-01-04 13:37:25 +00:00
// if true, the event will be added to the event log
// otherwise, it will only be used for internal purposes
fn notable(&self) -> bool;
2022-12-31 07:54:18 +00:00
}
impl Event {
2023-01-04 18:02:44 +00:00
#[allow(dead_code)]
2022-12-31 07:54:18 +00:00
pub fn description(&self) -> String {
format!("{}: {}", self.time, self.effect.description())
}
}
impl GameState {
pub fn new(world: World) -> GameState {
let mut events = Vec::new();
events.push(Box::new(Event {
time: Time { time: 0 },
effect: Box::new(WorldGenesis),
}));
GameState {
time: Time { time: 0 },
2023-01-04 13:37:25 +00:00
creatures: HashMap::new(),
2023-01-05 19:14:27 +00:00
items: HashMap::new(),
2022-12-31 07:54:18 +00:00
world: world,
events: events,
2022-12-31 13:03:24 +00:00
tavern: None,
2022-12-31 07:54:18 +00:00
}
}
2023-01-04 16:52:58 +00:00
pub fn set_tavern(&mut self, tavern: EntityId) {
2022-12-31 13:03:24 +00:00
self.tavern = Some(tavern);
}
2023-01-08 10:57:13 +00:00
pub fn apply_action(&mut self, action: Box<dyn Action>) {
let mut event = Event {
time: self.time,
effect: action,
};
2022-12-31 07:54:18 +00:00
event.effect.apply(self);
self.events.push(Box::new(event));
}
2022-12-31 13:03:24 +00:00
/**
* Getters
*/
2023-01-04 13:37:25 +00:00
pub fn guests(&self) -> Vec<EntityId> {
2022-12-31 13:03:24 +00:00
match &self.tavern {
Some(tavern) => {
2023-01-04 16:52:58 +00:00
let loc = self.world.get_site_location(*tavern);
2023-01-04 13:37:25 +00:00
self.creatures.values().filter(|c| {
2023-01-07 09:08:42 +00:00
c.loc == loc
2023-01-04 13:37:25 +00:00
}).map(|p| p.entity.id).collect::<Vec<_>>()
// Vec::new()
2022-12-31 13:03:24 +00:00
},
None => Vec::new(),
2022-12-31 14:22:44 +00:00
}
}
2023-01-07 09:08:42 +00:00
pub fn get_creature(&self, id: EntityId) -> Option<&Creature> {
2023-01-04 13:37:25 +00:00
self.creatures.get(&id)
2022-12-31 13:03:24 +00:00
}
2022-12-31 15:04:07 +00:00
2022-12-31 13:03:24 +00:00
/**
* Function to populate the world at genesis
*/
2022-12-31 07:54:18 +00:00
pub fn found_town(&mut self) {
let mut rng = rand::thread_rng();
loop {
let x = rng.gen_range(0..self.world.size);
let y = rng.gen_range(0..self.world.size);
if
self.world.map[x][y].terrain == Terrain::Flats ||
self.world.map[x][y].terrain == Terrain::Hills
{
2023-01-04 16:52:58 +00:00
let town = Town::new();
2023-01-08 10:57:13 +00:00
self.apply_action(Box::new(FoundTown {
loc: Location{ x: x as i32, y: y as i32 },
town: town.clone(),
}));
2022-12-31 08:38:01 +00:00
let pop_size = rng.gen_range(20..200);
for _ in 0..pop_size {
2023-01-08 10:57:13 +00:00
self.apply_action(Box::new(PersonGenesis {
town: town.clone(),
person: CreatureGenerator::create_human(
self.time.substract_years(rng.gen_range(18..30)),
Location { x: x as i32, y: y as i32 },
)
}));
2022-12-31 08:38:01 +00:00
}
2022-12-31 07:54:18 +00:00
break;
}
}
}
2022-12-31 08:38:01 +00:00
2023-01-07 09:08:42 +00:00
pub fn add_person(&mut self, mut creature: Creature) -> EntityId {
2023-01-04 13:37:25 +00:00
let id = (self.creatures.len() + 1) as u32; // avoid 0 id
2023-01-07 09:08:42 +00:00
creature.entity.id.1 = id;
let id = creature.entity.id;
2023-01-04 13:37:25 +00:00
self.creatures.insert(id, creature);
2023-01-07 09:08:42 +00:00
id
2022-12-31 08:38:01 +00:00
}
2022-12-31 13:03:24 +00:00
2023-01-05 19:14:27 +00:00
pub(crate) fn add_item(&mut self, mut item: Item) -> EntityId {
let id = (self.items.len() + 1) as u32; // avoid 0 id
2023-01-07 09:08:42 +00:00
item.entity.id.1 = id;
let id = item.entity.id;
2023-01-05 19:14:27 +00:00
self.items.insert(id, item);
2023-01-07 09:08:42 +00:00
id
2023-01-05 19:14:27 +00:00
}
2022-12-31 13:03:24 +00:00
pub fn build_tavern(&mut self) {
let mut rng = rand::thread_rng();
loop {
let x = rng.gen_range(0..self.world.size);
let y = rng.gen_range(0..self.world.size);
if
self.world.map[x][y].terrain == Terrain::Flats ||
self.world.map[x][y].terrain == Terrain::Hills
{
2023-01-08 10:57:13 +00:00
self.apply_action(Box::new(TavernBuilt {
loc: Location{ x: x as i32, y: y as i32 },
tavern: Tavern::new(),
}));
2022-12-31 14:22:44 +00:00
break;
2022-12-31 13:03:24 +00:00
}
}
}
2023-01-05 19:14:27 +00:00
2023-01-07 08:50:09 +00:00
pub fn claim_item(&mut self, new_owner_id: EntityId, item_id: EntityId) {
let mut item = self.items.get_mut(&item_id).unwrap();
2023-01-07 09:08:42 +00:00
item.owner = ItemOwner::Held(new_owner_id.clone());
2023-01-07 08:50:09 +00:00
}
2023-01-08 10:57:13 +00:00
pub fn add_coins(&mut self, id: EntityId, coins: u32) {
match id.0 {
EntityType::Creature => {
let mut creature = self.creatures.get(&id).unwrap().clone();
creature.coins += coins;
self.creatures.insert(id, creature);
},
EntityType::Item => {},
EntityType::Site => {
self.world.add_coins(id, coins);
},
}
}
pub fn pay_upkeep(&mut self, id: EntityId) {
match id.0 {
EntityType::Creature => {
let mut creature = self.creatures.get(&id).unwrap().clone();
let site = self.world.get_site_at(creature.loc);
match site {
Some(site) => {
let upkeep = 1;
if creature.coins >= upkeep {
creature.coins -= upkeep;
self.creatures.insert(id, creature);
self.add_coins(site.entity.id, upkeep);
} else {
// TODO: punish
}
},
None => {},
}
},
EntityType::Item => {},
EntityType::Site => {},
}
}
2022-12-31 14:22:44 +00:00
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_found_town() {
let mut state = GameState::new(World::new(1));
state.world.map[0][0].terrain = Terrain::Flats;
2023-01-01 20:11:27 +00:00
state.time = Time { time: 1e6 as i32 };
2022-12-31 14:22:44 +00:00
state.found_town();
2023-01-04 13:37:25 +00:00
assert_ne!(state.creatures.len(), 0);
2022-12-31 14:22:44 +00:00
}
#[test]
fn test_build_tavern() {
let mut state = GameState::new(World::new(2));
state.world.map[0][0].terrain = Terrain::Flats;
state.world.map[0][1].terrain = Terrain::Flats;
state.world.map[1][0].terrain = Terrain::Hills;
state.world.map[1][1].terrain = Terrain::Hills;
state.build_tavern();
assert_eq!(state.tavern.is_some(), true);
}
2023-01-04 13:37:25 +00:00
2022-12-30 20:30:12 +00:00
}