mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
travelers say where they're going
This commit is contained in:
parent
9be6c7b527
commit
c026b4d20a
@ -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(),
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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(),
|
||||
)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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),
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
@ -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(
|
||||
|
@ -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>,
|
||||
|
Loading…
Reference in New Issue
Block a user