travelers say where they're going

This commit is contained in:
IsseW 2022-08-16 12:09:23 +02:00 committed by Joshua Barretto
parent 9be6c7b527
commit c026b4d20a
7 changed files with 134 additions and 107 deletions

View File

@ -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<Vec3<f32>>,
pub heading_to: Option<String>,
/// 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<f32>) -> Self {
Self {
travel_to: Some(pos),
heading_to: None,
speed_factor: 0.5,
events: Vec::new(),
}

View File

@ -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_::<i32>() / 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

View File

@ -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_::<i32>() / TerrainChunkSize::RECT_SIZE.as_()).and_then(|chunk| {
data.sites.world_site_map.get(chunk.sites.first()?).copied()
});
}
});

View File

@ -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<comp::agent::Mark> {
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(),
)
});
}
});
}

View File

@ -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),
};
///////////////////////////////////////////////////////////

View File

@ -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(

View File

@ -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<world::World>>,
pub rtsim_entity: ReadStorage<'a, RtSimEntity>,
//pub rtsim_entities: ReadStorage<'a, RtSimEntity>,
pub buffs: ReadStorage<'a, Buffs>,
pub combos: ReadStorage<'a, Combo>,