From f40cfb4ac32d95ef8afa68560d0f2f6877039fa5 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 14 Aug 2022 16:08:10 +0100 Subject: [PATCH] Made farmers sell food --- common/src/rtsim.rs | 26 ++++++++++++++++++++ rtsim/src/data/npc.rs | 11 +-------- server/src/rtsim2/tick.rs | 36 +++++++++++++++++----------- world/src/site/settlement/mod.rs | 41 ++++++++++++++++++++++---------- 4 files changed, 78 insertions(+), 36 deletions(-) diff --git a/common/src/rtsim.rs b/common/src/rtsim.rs index 3852d09190..bd5684a6d5 100644 --- a/common/src/rtsim.rs +++ b/common/src/rtsim.rs @@ -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(), + } + } +} diff --git a/rtsim/src/data/npc.rs b/rtsim/src/data/npc.rs index bc0594d608..8d6e71f1de 100644 --- a/rtsim/src/data/npc.rs +++ b/rtsim/src/data/npc.rs @@ -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 { diff --git a/server/src/rtsim2/tick.rs b/server/src/rtsim2/tick.rs index 8566d9d653..1249db34be 100644 --- a/server/src/rtsim2/tick.rs +++ b/server/src/rtsim2/tick.rs @@ -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), diff --git a/world/src/site/settlement/mod.rs b/world/src/site/settlement/mod.rs index 79f027b004..c77e8e24b2 100644 --- a/world/src/site/settlement/mod.rs +++ b/world/src/site/settlement/mod.rs @@ -1011,6 +1011,15 @@ fn humanoid(pos: Vec3, 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 = 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 - stockmap - .entry(Good::Food) - .and_modify(|e| *e = e.max(10_000.0)) - .or_insert(10_000.0); + 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 - stockmap - .entry(Good::Potions) - .and_modify(|e| *e = e.powf(0.25)); + 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 - stockmap - .entry(Good::Coin) - .and_modify(|e| *e = e.min(rng.gen_range(1000.0..3000.0))); + 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))