start of professions and items
This commit is contained in:
parent
4b5ce102e0
commit
717be3a32f
110
src/creature.rs
110
src/creature.rs
|
@ -1,17 +1,20 @@
|
|||
use std::{fmt::Display};
|
||||
use rand::prelude::*;
|
||||
|
||||
use crate::{time::Time, world::{World}, generators::PersonNameGenerator, state::{GameState, Action}, entity::{Entity, Location}};
|
||||
use crate::{time::Time, world::{World}, generators::PersonNameGenerator, state::{GameState, Action}, entity::{Entity, Location, EntityId}, item::ItemGenerator, events::ItemCrafted};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Profession {
|
||||
Peasant,
|
||||
Adventurer,
|
||||
Blacksmith,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Agenda {
|
||||
Idle(u32),
|
||||
Traveling(Location),
|
||||
Idle(u32), // number of days to idle
|
||||
Traveling(Location), // destination
|
||||
Craft,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -21,16 +24,75 @@ pub struct Creature {
|
|||
pub birth_date: Time,
|
||||
pub profession: Profession,
|
||||
pub agenda: Agenda,
|
||||
pub inventory: Vec<EntityId>,
|
||||
pub weapon: Option<EntityId>,
|
||||
pub armor: Option<EntityId>,
|
||||
}
|
||||
|
||||
pub struct CreatureGenerator;
|
||||
|
||||
impl Display for Profession {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Profession::Peasant => write!(f, "Peasant"),
|
||||
Profession::Adventurer => write!(f, "Adventurer"),
|
||||
Profession::Blacksmith => write!(f, "Blacksmith"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Creature {
|
||||
pub fn new(birth_date: Time, location: Location) -> Creature {
|
||||
pub fn new(birth_date: Time, location: Location, profession: Profession) -> Creature {
|
||||
Creature {
|
||||
entity: Entity { id: 0, loc: location },
|
||||
name: PersonNameGenerator::name(),
|
||||
birth_date: birth_date,
|
||||
profession: Profession::Peasant,
|
||||
profession: profession,
|
||||
agenda: Agenda::Idle(0),
|
||||
inventory: Vec::new(),
|
||||
weapon: None,
|
||||
armor: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn travel_to_random_location(&self, world: &World) -> Agenda {
|
||||
let mut rng = rand::thread_rng();
|
||||
let dest = world.sites.keys().choose(&mut rng);
|
||||
if let Some(dest) = dest {
|
||||
Agenda::Traveling(*dest)
|
||||
} else {
|
||||
Agenda::Idle(1)
|
||||
}
|
||||
}
|
||||
|
||||
fn select_peasant_agenda(&self, _world: &World) -> Agenda {
|
||||
Agenda::Idle(10)
|
||||
}
|
||||
|
||||
fn select_adventurer_agenda(&self, world: &World) -> Agenda {
|
||||
self.travel_to_random_location(world)
|
||||
}
|
||||
|
||||
fn select_blacksmith_agenda(&self, _world: &World) -> Agenda {
|
||||
let mut rng = rand::thread_rng();
|
||||
let p = rng.gen_range(0.0..1.0);
|
||||
if p < 0.1 {
|
||||
Agenda::Idle(10)
|
||||
} else if p < 0.55 {
|
||||
Agenda::Craft
|
||||
} else {
|
||||
self.travel_to_random_location(_world)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn select_agenda(&self, world: &World) -> Agenda {
|
||||
match self.profession {
|
||||
Profession::Peasant => self.select_peasant_agenda(world),
|
||||
Profession::Adventurer => self.select_adventurer_agenda(world),
|
||||
Profession::Blacksmith => self.select_blacksmith_agenda(world),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,9 +102,7 @@ impl Creature {
|
|||
// 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());
|
||||
self.agenda = self.select_agenda(world);
|
||||
} else {
|
||||
self.agenda = Agenda::Idle(days - 1);
|
||||
}
|
||||
|
@ -66,6 +126,14 @@ impl Creature {
|
|||
}
|
||||
Vec::new()
|
||||
},
|
||||
Agenda::Craft => {
|
||||
vec![
|
||||
Box::new(ItemCrafted {
|
||||
crafter: self.entity.id,
|
||||
item: ItemGenerator::generate_item(),
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +153,9 @@ impl Creature {
|
|||
},
|
||||
None => return format!("I'm traveling to an unknown location"),
|
||||
}
|
||||
},
|
||||
Agenda::Craft => {
|
||||
return format!("I'm crafting");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +167,23 @@ impl Display for Creature {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl CreatureGenerator {
|
||||
pub fn create_human(birth_date: Time, location: Location) -> Creature {
|
||||
// pick random profession
|
||||
let mut rng = rand::thread_rng();
|
||||
let profession = rng.gen_range(0..3);
|
||||
let profession = match profession {
|
||||
0 => Profession::Peasant,
|
||||
1 => Profession::Adventurer,
|
||||
2 => Profession::Blacksmith,
|
||||
_ => panic!("Invalid profession"),
|
||||
};
|
||||
Creature::new(birth_date, location, profession)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{world::{World}, site::{Site, Town, Structure}};
|
||||
|
@ -104,13 +192,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_person_creation() {
|
||||
let person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0});
|
||||
let person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0}, Profession::Peasant);
|
||||
assert_ne!(person.name, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_traveling() {
|
||||
let mut person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0});
|
||||
let mut person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0}, Profession::Peasant);
|
||||
person.agenda = Agenda::Traveling(Location{x: 10, y: 0});
|
||||
person.step(&World::new(32));
|
||||
assert_eq!(person.entity.loc, Location{x: 1, y: 0});
|
||||
|
@ -118,7 +206,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_start_traveling() {
|
||||
let mut person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0});
|
||||
let mut person = Creature::new(Time { time: 0 }, Location{x: 0, y: 0}, Profession::Peasant);
|
||||
person.agenda = Agenda::Idle(0);
|
||||
let mut world = World::new(32);
|
||||
world.add_site(Site{
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
use crate::{entity::EntityId, item::Item, state::{Action, GameState, self}};
|
||||
|
||||
pub struct ItemCrafted {
|
||||
pub crafter: EntityId,
|
||||
pub item: Item,
|
||||
}
|
||||
|
||||
impl Action for ItemCrafted {
|
||||
fn apply(&self, state: &mut GameState) {
|
||||
state.add_item(self.item.clone());
|
||||
}
|
||||
|
||||
fn description(&self) -> String {
|
||||
format!("{} crafted", self.item.name)
|
||||
}
|
||||
|
||||
fn notable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
|
@ -2,8 +2,10 @@ mod found_town;
|
|||
mod world_genesis;
|
||||
mod person_genesis;
|
||||
mod tavern_built;
|
||||
mod item;
|
||||
|
||||
pub use found_town::FoundTown;
|
||||
pub use world_genesis::WorldGenesis;
|
||||
pub use person_genesis::PersonGenesis;
|
||||
pub use tavern_built::TavernBuilt;
|
||||
pub use item::ItemCrafted;
|
|
@ -0,0 +1,44 @@
|
|||
use crate::entity::{Entity, Location};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ItemType {
|
||||
Weapon(Weapon),
|
||||
Armor(Armor),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Item {
|
||||
pub entity: Entity,
|
||||
pub name: String,
|
||||
pub item_type: ItemType,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Weapon {
|
||||
pub damage_base: u32,
|
||||
pub damage_dice: u32,
|
||||
pub damage_sides: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Armor {
|
||||
pub armor_class: u32,
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct ItemGenerator;
|
||||
|
||||
impl ItemGenerator {
|
||||
pub fn generate_item() -> Item {
|
||||
Item {
|
||||
entity: Entity { id: 0, loc: Location{ x: 0, y: 0 } },
|
||||
name: "Sword".to_string(),
|
||||
item_type: ItemType::Weapon(Weapon {
|
||||
damage_base: 0,
|
||||
damage_dice: 1,
|
||||
damage_sides: 6,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ mod site;
|
|||
mod ui;
|
||||
mod entity;
|
||||
mod game;
|
||||
mod item;
|
||||
|
||||
use ui::App;
|
||||
use noise::{Perlin, ScalePoint, Add, NoiseFn, ScaleBias};
|
||||
|
|
19
src/state.rs
19
src/state.rs
|
@ -3,7 +3,8 @@ use std::collections::HashMap;
|
|||
|
||||
use rand::prelude::*;
|
||||
use crate::entity::{Location, EntityId};
|
||||
use crate::creature::Creature;
|
||||
use crate::creature::{Creature, Profession, CreatureGenerator};
|
||||
use crate::item::Item;
|
||||
use crate::site::{Town, Tavern};
|
||||
use crate::time::Time;
|
||||
use crate::world::{World, Terrain};
|
||||
|
@ -12,6 +13,7 @@ pub struct GameState {
|
|||
pub time: Time,
|
||||
pub world: World,
|
||||
pub creatures: HashMap<u32, Creature>,
|
||||
pub items: HashMap<u32, Item>,
|
||||
pub events: Vec<Box<Event>>,
|
||||
pub tavern: Option<EntityId>,
|
||||
}
|
||||
|
@ -52,6 +54,7 @@ impl GameState {
|
|||
GameState {
|
||||
time: Time { time: 0 },
|
||||
creatures: HashMap::new(),
|
||||
items: HashMap::new(),
|
||||
world: world,
|
||||
events: events,
|
||||
tavern: None,
|
||||
|
@ -119,10 +122,10 @@ impl GameState {
|
|||
time: self.time,
|
||||
effect: Box::new(PersonGenesis {
|
||||
town: town.clone(),
|
||||
person: Creature::new(
|
||||
person: CreatureGenerator::create_human(
|
||||
self.time.substract_years(rng.gen_range(18..30)),
|
||||
Location { x: x as i32, y: y as i32 }
|
||||
),
|
||||
Location { x: x as i32, y: y as i32 },
|
||||
)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
@ -137,6 +140,13 @@ impl GameState {
|
|||
self.creatures.insert(id, creature);
|
||||
}
|
||||
|
||||
pub(crate) fn add_item(&mut self, mut item: Item) -> EntityId {
|
||||
let id = (self.items.len() + 1) as u32; // avoid 0 id
|
||||
item.entity.id = id;
|
||||
self.items.insert(id, item);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn build_tavern(&mut self) {
|
||||
let mut rng = rand::thread_rng();
|
||||
loop {
|
||||
|
@ -157,6 +167,7 @@ impl GameState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -238,7 +238,8 @@ impl<'a> App<'a> {
|
|||
self.conversation.add_line(ChatLine::new(
|
||||
guest_id.unwrap(),
|
||||
guest.name.clone(),
|
||||
"Hello, I'm ".to_owned() + &guest.name + ".",
|
||||
"Hello, I'm ".to_owned() + &guest.name + ", nice to meet you! "
|
||||
+ "I'm a " + &guest.profession.to_string() + ".",
|
||||
false
|
||||
));
|
||||
self.conversation_scroll = 0;
|
||||
|
|
Loading…
Reference in New Issue