Made farmers sell food

This commit is contained in:
Joshua Barretto 2022-08-14 16:08:10 +01:00
parent e204789ce9
commit f40cfb4ac3
4 changed files with 78 additions and 36 deletions

View File

@ -93,3 +93,29 @@ pub enum ChunkResource {
#[serde(rename = "2")]
Cotton,
}
#[derive(Clone, Serialize, Deserialize)]
pub enum Profession {
#[serde(rename = "0")]
Farmer,
#[serde(rename = "1")]
Hunter,
#[serde(rename = "2")]
Merchant,
#[serde(rename = "3")]
Guard,
#[serde(rename = "4")]
Adventurer(u32),
}
impl Profession {
pub fn to_name(&self) -> String {
match self {
Self::Farmer => "Farmer".to_string(),
Self::Hunter => "Hunter".to_string(),
Self::Merchant => "Merchant".to_string(),
Self::Guard => "Guard".to_string(),
Self::Adventurer(_) => "Adventurer".to_string(),
}
}
}

View File

@ -11,16 +11,7 @@ use common::{
comp,
};
use world::util::RandomPerm;
pub use common::rtsim::NpcId;
#[derive(Clone, Serialize, Deserialize)]
pub enum Profession {
Farmer,
Hunter,
Merchant,
Guard,
Adventurer(u32),
}
pub use common::rtsim::{NpcId, Profession};
#[derive(Copy, Clone, Default)]
pub enum NpcMode {

View File

@ -9,6 +9,7 @@ use common::{
resources::{DeltaTime, Time, TimeOfDay},
rtsim::{RtSimController, RtSimEntity},
slowjob::SlowJobPool,
trade::Good,
LoadoutBuilder,
SkillSetBuilder,
};
@ -16,7 +17,7 @@ use common_ecs::{Job, Origin, Phase, System};
use rtsim2::data::npc::{NpcMode, Profession};
use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
use std::{sync::Arc, time::Duration};
use world::site::settlement::merchant_loadout;
use world::site::settlement::{merchant_loadout, trader_loadout};
#[derive(Default)]
pub struct Sys;
@ -58,6 +59,7 @@ impl<'a> System<'a> for Sys {
let mut emitter = server_event_bus.emitter();
let rtsim = &mut *rtsim;
rtsim.state.data_mut().time_of_day = *time_of_day;
rtsim.state.tick(&world, index.as_index_ref(), *time_of_day, *time, dt.0);
if rtsim
@ -84,23 +86,26 @@ impl<'a> System<'a> for Sys {
let mut loadout_builder = LoadoutBuilder::from_default(&body);
let mut rng = npc.rng(3);
let economy = npc.home
.and_then(|home| {
let site = data.sites.get(home)?.world_site?;
index.sites.get(site).trade_information(site.id())
});
if let Some(ref profession) = npc.profession {
loadout_builder = match profession {
Profession::Guard => loadout_builder
.with_asset_expect("common.loadout.village.guard", &mut rng),
Profession::Merchant => {
merchant_loadout(
loadout_builder,
npc.home
.and_then(|home| {
let site = data.sites.get(home)?.world_site?;
index.sites.get(site).trade_information(site.id())
}).as_ref(),
)
}
Profession::Merchant => merchant_loadout(loadout_builder, economy.as_ref()),
Profession::Farmer | Profession::Hunter => loadout_builder
Profession::Farmer => trader_loadout(
loadout_builder
.with_asset_expect("common.loadout.village.villager", &mut rng),
economy.as_ref(),
|good| matches!(good, Good::Food),
),
Profession::Hunter => loadout_builder
.with_asset_expect("common.loadout.village.villager", &mut rng),
Profession::Adventurer(level) => todo!(),
@ -109,7 +114,7 @@ impl<'a> System<'a> for Sys {
let can_speak = npc.profession.is_some(); // TODO: not this
let trade_for_site = if let Some(Profession::Merchant) = npc.profession {
let trade_for_site = if let Some(Profession::Merchant | Profession::Farmer) = npc.profession {
npc.home.and_then(|home| Some(data.sites.get(home)?.world_site?.id()))
} else {
None
@ -121,7 +126,10 @@ impl<'a> System<'a> for Sys {
.unwrap_or(0);
emitter.emit(ServerEvent::CreateNpc {
pos: comp::Pos(npc.wpos),
stats: comp::Stats::new("Rtsim NPC".to_string()),
stats: comp::Stats::new(npc.profession
.as_ref()
.map(|p| p.to_name())
.unwrap_or_else(|| "Rtsim NPC".to_string())),
skill_set: skill_set,
health: Some(comp::Health::new(body, health_level)),
poise: comp::Poise::new(body),

View File

@ -1011,6 +1011,15 @@ fn humanoid(pos: Vec3<f32>, economy: &SiteInformation, dynamic_rng: &mut impl Rn
pub fn merchant_loadout(
loadout_builder: LoadoutBuilder,
economy: Option<&SiteInformation>,
) -> LoadoutBuilder {
trader_loadout(loadout_builder
.with_asset_expect("common.loadout.village.merchant", &mut thread_rng()), economy, |_| true)
}
pub fn trader_loadout(
loadout_builder: LoadoutBuilder,
economy: Option<&SiteInformation>,
mut permitted: impl FnMut(Good) -> bool,
) -> LoadoutBuilder {
let rng = &mut thread_rng();
@ -1021,7 +1030,10 @@ pub fn merchant_loadout(
let mut bag4 = Item::new_from_asset_expect("common.items.armor.misc.bag.sturdy_red_backpack");
let slots = backpack.slots().len() + 4 * bag1.slots().len();
let mut stockmap: HashMap<Good, f32> = economy
.map(|e| e.unconsumed_stock.clone())
.map(|e| e.unconsumed_stock.clone()
.into_iter()
.filter(|(good, _)| permitted(*good))
.collect())
.unwrap_or_default();
// modify stock for better gameplay
@ -1029,21 +1041,27 @@ pub fn merchant_loadout(
// for the players to buy; the `.max` is temporary to ensure that there's some
// food for sale at every site, to be used until we have some solution like NPC
// houses as a limit on econsim population growth
if permitted(Good::Food) {
stockmap
.entry(Good::Food)
.and_modify(|e| *e = e.max(10_000.0))
.or_insert(10_000.0);
}
// Reduce amount of potions so merchants do not oversupply potions.
// TODO: Maybe remove when merchants and their inventories are rtsim?
// Note: Likely without effect now that potions are counted as food
if permitted(Good::Potions) {
stockmap
.entry(Good::Potions)
.and_modify(|e| *e = e.powf(0.25));
}
// It's safe to truncate here, because coins clamped to 3000 max
// also we don't really want negative values here
if permitted(Good::Coin) {
stockmap
.entry(Good::Coin)
.and_modify(|e| *e = e.min(rng.gen_range(1000.0..3000.0)));
}
// assume roughly 10 merchants sharing a town's stock (other logic for coins)
stockmap
.iter_mut()
@ -1073,7 +1091,6 @@ pub fn merchant_loadout(
transfer(&mut wares, &mut bag4);
loadout_builder
.with_asset_expect("common.loadout.village.merchant", rng)
.back(Some(backpack))
.bag(ArmorSlot::Bag1, Some(bag1))
.bag(ArmorSlot::Bag2, Some(bag2))