From c026b4d20a620e8b90b79093993e945d728c0036 Mon Sep 17 00:00:00 2001 From: IsseW Date: Tue, 16 Aug 2022 12:09:23 +0200 Subject: [PATCH] travelers say where they're going --- common/src/rtsim.rs | 3 + rtsim/src/rule/npc_ai.rs | 6 +- rtsim/src/rule/simulate_npcs.rs | 3 - server/src/rtsim2/tick.rs | 80 ++++++---- server/src/sys/agent.rs | 4 +- .../sys/agent/behavior_tree/interaction.rs | 140 +++++++++--------- server/src/sys/agent/data.rs | 5 +- 7 files changed, 134 insertions(+), 107 deletions(-) diff --git a/common/src/rtsim.rs b/common/src/rtsim.rs index 4202c36bcd..8064459c40 100644 --- a/common/src/rtsim.rs +++ b/common/src/rtsim.rs @@ -60,6 +60,7 @@ pub struct RtSimController { /// toward the given location, accounting for obstacles and other /// high-priority situations like being attacked. pub travel_to: Option>, + pub heading_to: Option, /// Proportion of full speed to move pub speed_factor: f32, /// Events @@ -70,6 +71,7 @@ impl Default for RtSimController { fn default() -> Self { Self { travel_to: None, + heading_to: None, speed_factor: 1.0, events: Vec::new(), } @@ -80,6 +82,7 @@ impl RtSimController { pub fn with_destination(pos: Vec3) -> Self { Self { travel_to: Some(pos), + heading_to: None, speed_factor: 0.5, events: Vec::new(), } diff --git a/rtsim/src/rule/npc_ai.rs b/rtsim/src/rule/npc_ai.rs index 6eabd789fc..9f43a7b265 100644 --- a/rtsim/src/rule/npc_ai.rs +++ b/rtsim/src/rule/npc_ai.rs @@ -10,7 +10,7 @@ use common::{ path::Path, rtsim::{Profession, SiteId}, store::Id, - terrain::TerrainChunkSize, + terrain::TerrainChunkSize, vol::RectVolSize, }; use fxhash::FxHasher64; use itertools::Itertools; @@ -236,6 +236,10 @@ impl Rule for NpcAi { let data = &mut *ctx.state.data_mut(); let mut dynamic_rng = rand::thread_rng(); for npc in data.npcs.values_mut() { + npc.current_site = ctx.world.sim().get(npc.wpos.xy().as_::() / TerrainChunkSize::RECT_SIZE.as_()).and_then(|chunk| { + data.sites.world_site_map.get(chunk.sites.first()?).copied() + }); + if let Some(home_id) = npc.home { if let Some((target, _)) = npc.target { // Walk to the current target diff --git a/rtsim/src/rule/simulate_npcs.rs b/rtsim/src/rule/simulate_npcs.rs index 000fa14cb7..e1fb91f856 100644 --- a/rtsim/src/rule/simulate_npcs.rs +++ b/rtsim/src/rule/simulate_npcs.rs @@ -36,9 +36,6 @@ impl Rule for SimulateNpcs { npc.wpos.z = ctx.world.sim() .get_alt_approx(npc.wpos.xy().map(|e| e as i32)) .unwrap_or(0.0); - npc.current_site = ctx.world.sim().get(npc.wpos.xy().as_::() / TerrainChunkSize::RECT_SIZE.as_()).and_then(|chunk| { - data.sites.world_site_map.get(chunk.sites.first()?).copied() - }); } }); diff --git a/server/src/rtsim2/tick.rs b/server/src/rtsim2/tick.rs index 30d28975cf..0c88b14836 100644 --- a/server/src/rtsim2/tick.rs +++ b/server/src/rtsim2/tick.rs @@ -10,32 +10,34 @@ use common::{ rtsim::{RtSimController, RtSimEntity}, slowjob::SlowJobPool, trade::{Good, SiteInformation}, - LoadoutBuilder, - SkillSetBuilder, + LoadoutBuilder, SkillSetBuilder, }; use common_ecs::{Job, Origin, Phase, System}; -use rtsim2::data::{npc::{NpcMode, Profession}, Npc, Sites}; +use rtsim2::data::{ + npc::{NpcMode, Profession}, + Npc, Sites, +}; use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage}; use std::{sync::Arc, time::Duration}; use world::site::settlement::trader_loadout; fn humanoid_config(profession: &Profession) -> &'static str { match profession { - Profession::Farmer | Profession::Hunter => "common.entity.village.villager", - Profession::Merchant => "common.entity.village.merchant", - Profession::Guard => "common.entity.village.guard", - Profession::Adventurer(rank) => match rank { - 0 => "common.entity.world.traveler0", - 1 => "common.entity.world.traveler1", - 2 => "common.entity.world.traveler2", - 3 => "common.entity.world.traveler3", - _ => panic!("Not a valid adventurer rank"), - }, - Profession::Blacksmith => "common.entity.village.blacksmith", - Profession::Chef => "common.entity.village.chef", - Profession::Alchemist => "common.entity.village.alchemist", - Profession::Pirate => "common.entity.spot.pirate", - Profession::Cultist => "common.entity.dungeon.tier-5.cultist", + Profession::Farmer | Profession::Hunter => "common.entity.village.villager", + Profession::Merchant => "common.entity.village.merchant", + Profession::Guard => "common.entity.village.guard", + Profession::Adventurer(rank) => match rank { + 0 => "common.entity.world.traveler0", + 1 => "common.entity.world.traveler1", + 2 => "common.entity.world.traveler2", + 3 => "common.entity.world.traveler3", + _ => panic!("Not a valid adventurer rank"), + }, + Profession::Blacksmith => "common.entity.village.blacksmith", + Profession::Chef => "common.entity.village.chef", + Profession::Alchemist => "common.entity.village.alchemist", + Profession::Pirate => "common.entity.spot.pirate", + Profession::Cultist => "common.entity.dungeon.tier-5.cultist", } } @@ -68,10 +70,14 @@ fn blacksmith_loadout( loadout_builder: LoadoutBuilder, economy: Option<&SiteInformation>, ) -> LoadoutBuilder { - trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Tools | Good::Armor)) + trader_loadout(loadout_builder, economy, |good| { + matches!(good, Good::Tools | Good::Armor) + }) } -fn profession_extra_loadout(profession: Option<&Profession>) -> fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder { +fn profession_extra_loadout( + profession: Option<&Profession>, +) -> fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder { match profession { Some(Profession::Merchant) => merchant_loadout, Some(Profession::Farmer) => farmer_loadout, @@ -83,7 +89,9 @@ fn profession_extra_loadout(profession: Option<&Profession>) -> fn(LoadoutBuilde fn profession_agent_mark(profession: Option<&Profession>) -> Option { match profession { - Some(Profession::Merchant | Profession::Farmer | Profession::Chef | Profession::Blacksmith) => Some(comp::agent::Mark::Merchant), + Some( + Profession::Merchant | Profession::Farmer | Profession::Chef | Profession::Blacksmith, + ) => Some(comp::agent::Mark::Merchant), Some(Profession::Guard) => Some(comp::agent::Mark::Guard), _ => None, } @@ -94,16 +102,15 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo let pos = comp::Pos(npc.wpos); if let Some(ref profession) = npc.profession { + let economy = npc.home.and_then(|home| { + let site = sites.get(home)?.world_site?; + index.sites.get(site).trade_information(site.id()) + }); - let economy = npc.home - .and_then(|home| { - let site = sites.get(home)?.world_site?; - index.sites.get(site).trade_information(site.id()) - }); - let config_asset = humanoid_config(profession); - let entity_config = EntityConfig::from_asset_expect_owned(config_asset).with_body(BodyBuilder::Exact(body)); + let entity_config = + EntityConfig::from_asset_expect_owned(config_asset).with_body(BodyBuilder::Exact(body)); let mut rng = npc.rng(3); EntityInfo::at(pos.0) .with_entity_config(entity_config, Some(config_asset), &mut rng) @@ -160,7 +167,9 @@ impl<'a> System<'a> for Sys { 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); + rtsim + .state + .tick(&world, index.as_index_ref(), *time_of_day, *time, dt.0); if rtsim .last_saved @@ -226,8 +235,7 @@ impl<'a> System<'a> for Sys { for (pos, rtsim_entity, agent) in (&positions, &rtsim_entities, (&mut agents).maybe()).join() { - data - .npcs + data.npcs .get_mut(rtsim_entity.0) .filter(|npc| matches!(npc.mode, NpcMode::Loaded)) .map(|npc| { @@ -238,6 +246,16 @@ impl<'a> System<'a> for Sys { if let Some(agent) = agent { agent.rtsim_controller.travel_to = npc.target.map(|(wpos, _)| wpos); agent.rtsim_controller.speed_factor = npc.target.map_or(1.0, |(_, sf)| sf); + agent.rtsim_controller.heading_to = + npc.pathing.intersite_path.as_ref().and_then(|(path, _)| { + Some( + index + .sites + .get(data.sites.get(path.end)?.world_site?) + .name() + .to_string(), + ) + }); } }); } diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index adbe5b4bc6..3714e564a8 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -71,6 +71,7 @@ impl<'a> System<'a> for Sys { &mut controllers, read_data.light_emitter.maybe(), read_data.groups.maybe(), + read_data.rtsim_entities.maybe(), !&read_data.is_mounts, ) .par_join() @@ -93,6 +94,7 @@ impl<'a> System<'a> for Sys { controller, light_emitter, group, + rtsim_entity, _, )| { let mut event_emitter = event_bus.emitter(); @@ -180,6 +182,7 @@ impl<'a> System<'a> for Sys { // Package all this agent's data into a convenient struct let data = AgentData { entity: &entity, + rtsim_entity, uid, pos, vel, @@ -206,7 +209,6 @@ impl<'a> System<'a> for Sys { msm: &read_data.msm, poise: read_data.poises.get(entity), stance: read_data.stances.get(entity), - rtsim_entity: read_data.rtsim_entities.get(entity), }; /////////////////////////////////////////////////////////// diff --git a/server/src/sys/agent/behavior_tree/interaction.rs b/server/src/sys/agent/behavior_tree/interaction.rs index 29d2175f7e..86acde2c6d 100644 --- a/server/src/sys/agent/behavior_tree/interaction.rs +++ b/server/src/sys/agent/behavior_tree/interaction.rs @@ -107,88 +107,90 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool { match subject { Subject::Regular => { - /* - if let Some(rtsim_entity) = &bdata.rtsim_entity { - if matches!(rtsim_entity.kind, RtSimEntityKind::Prisoner) { - agent_data.chat_npc("npc-speech-prisoner", event_emitter); - } else if let Some((_travel_to, destination_name) = &agent.rtsim_controller.travel_to { - let personality = &rtsim_entity.brain.personality; - let standard_response_msg = || -> String { + if let Some(destination_name) = &agent.rtsim_controller.heading_to { + let msg = format!( + "I'm heading to {}! Want to come along?", + destination_name + ); + agent_data.chat_npc(msg, event_emitter); + } + /*if let ( + Some((_travel_to, destination_name)), + Some(rtsim_entity), + ) = (&agent.rtsim_controller.travel_to, &agent_data.rtsim_entity) + { + let personality = &rtsim_entity.brain.personality; + let standard_response_msg = || -> String { + if personality.will_ambush { + format!( + "I'm heading to {}! Want to come along? We'll make \ + great travel buddies, hehe.", + destination_name + ) + } else if personality + .personality_traits + .contains(PersonalityTrait::Extroverted) + { + format!( + "I'm heading to {}! Want to come along?", + destination_name + ) + } else if personality + .personality_traits + .contains(PersonalityTrait::Disagreeable) + { + "Hrm.".to_string() + } else { + "Hello!".to_string() + } + }; + let msg = if let Some(tgt_stats) = read_data.stats.get(target) { + agent.rtsim_controller.events.push(RtSimEvent::AddMemory( + Memory { + item: MemoryItem::CharacterInteraction { + name: tgt_stats.name.clone(), + }, + time_to_forget: read_data.time.0 + 600.0, + }, + )); + if rtsim_entity.brain.remembers_character(&tgt_stats.name) { if personality.will_ambush { - format!( - "I'm heading to {}! Want to come along? We'll make \ - great travel buddies, hehe.", - destination_name - ) + "Just follow me a bit more, hehe.".to_string() } else if personality .personality_traits .contains(PersonalityTrait::Extroverted) { - format!( - "I'm heading to {}! Want to come along?", - destination_name - ) - } else if personality - .personality_traits - .contains(PersonalityTrait::Disagreeable) - { - "Hrm.".to_string() - } else { - "Hello!".to_string() - } - }; - let msg = if let Some(tgt_stats) = read_data.stats.get(target) { - agent.rtsim_controller.events.push(RtSimEvent::AddMemory( - Memory { - item: MemoryItem::CharacterInteraction { - name: tgt_stats.name.clone(), - }, - time_to_forget: read_data.time.0 + 600.0, - }, - )); - if rtsim_entity.brain.remembers_character(&tgt_stats.name) { - if personality.will_ambush { - format!( - "I'm heading to {}! Want to come along? We'll \ - make great travel buddies, hehe.", - destination_name - ) - } else if personality + if personality .personality_traits .contains(PersonalityTrait::Extroverted) { - if personality - .personality_traits - .contains(PersonalityTrait::Extroverted) - { - format!( - "Greetings fair {}! It has been far \ - too long since last I saw you. I'm \ - going to {} right now.", - &tgt_stats.name, destination_name - ) - } else if personality - .personality_traits - .contains(PersonalityTrait::Disagreeable) - { - "Oh. It's you again.".to_string() - } else { - format!( - "Hi again {}! Unfortunately I'm in a \ - hurry right now. See you!", - &tgt_stats.name - ) - } + format!( + "Greetings fair {}! It has been far \ + too long since last I saw you. I'm \ + going to {} right now.", + &tgt_stats.name, destination_name + ) + } else if personality + .personality_traits + .contains(PersonalityTrait::Disagreeable) + { + "Oh. It's you again.".to_string() } else { - standard_response_msg() + format!( + "Hi again {}! Unfortunately I'm in a \ + hurry right now. See you!", + &tgt_stats.name + ) } } else { standard_response_msg() - }; - agent_data.chat_npc(msg, event_emitter); - } + } + } else { + standard_response_msg() + }; + agent_data.chat_npc(msg, event_emitter); } else*/ - if agent.behavior.can_trade(agent_data.alignment.copied(), by) { + else if agent.behavior.can_trade(agent_data.alignment.copied(), by) { if !agent.behavior.is(BehaviorState::TRADING) { controller.push_initiate_invite(by, InviteKind::Trade); agent_data.chat_npc( diff --git a/server/src/sys/agent/data.rs b/server/src/sys/agent/data.rs index e443e67cff..2d1e816128 100644 --- a/server/src/sys/agent/data.rs +++ b/server/src/sys/agent/data.rs @@ -9,9 +9,8 @@ use common::{ mounting::Mount, path::TraversalConfig, resources::{DeltaTime, Time, TimeOfDay}, - // rtsim::RtSimEntity, terrain::TerrainGrid, - uid::{Uid, UidAllocator}, + uid::{Uid, UidAllocator}, rtsim::RtSimEntity, }; use specs::{ shred::ResourceId, Entities, Entity as EcsEntity, Read, ReadExpect, ReadStorage, SystemData, @@ -21,6 +20,7 @@ use std::sync::Arc; pub struct AgentData<'a> { pub entity: &'a EcsEntity, + pub rtsim_entity: Option<&'a RtSimEntity>, //pub rtsim_entity: Option<&'a RtSimData>, pub uid: &'a Uid, pub pos: &'a Pos, @@ -153,6 +153,7 @@ pub struct ReadData<'a> { pub light_emitter: ReadStorage<'a, LightEmitter>, #[cfg(feature = "worldgen")] pub world: ReadExpect<'a, Arc>, + pub rtsim_entity: ReadStorage<'a, RtSimEntity>, //pub rtsim_entities: ReadStorage<'a, RtSimEntity>, pub buffs: ReadStorage<'a, Buffs>, pub combos: ReadStorage<'a, Combo>,